Blender  V2.93
indexer.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  * Peter Schlaile <peter [at] schlaile [dot] de> 2011
17  */
18 
23 #include <stdlib.h>
24 
25 #include "MEM_guardedalloc.h"
26 
27 #include "BLI_endian_switch.h"
28 #include "BLI_fileops.h"
29 #include "BLI_ghash.h"
30 #include "BLI_math.h"
31 #include "BLI_path_util.h"
32 #include "BLI_string.h"
33 #include "BLI_threads.h"
34 #include "BLI_utildefines.h"
35 #ifdef _WIN32
36 # include "BLI_winstuff.h"
37 #endif
38 
39 #include "IMB_anim.h"
40 #include "IMB_indexer.h"
41 #include "imbuf.h"
42 
43 #include "BKE_global.h"
44 
45 #ifdef WITH_AVI
46 # include "AVI_avi.h"
47 #endif
48 
49 #ifdef WITH_FFMPEG
50 # include "ffmpeg_compat.h"
51 # include <libavutil/imgutils.h>
52 #endif
53 
54 static const char binary_header_str[] = "BlenMIdx";
55 static const char temp_ext[] = "_part";
56 
58 static const float proxy_fac[] = {0.25, 0.50, 0.75, 1.00};
59 
60 #ifdef WITH_FFMPEG
61 static int tc_types[] = {
66 };
67 #endif
68 
69 #define INDEX_FILE_VERSION 2
70 
71 /* ----------------------------------------------------------------------
72  * - time code index functions
73  * ---------------------------------------------------------------------- */
74 
76 {
77 
78  anim_index_builder *rv = MEM_callocN(sizeof(struct anim_index_builder), "index builder");
79 
80  fprintf(stderr, "Starting work on index: %s\n", name);
81 
82  BLI_strncpy(rv->name, name, sizeof(rv->name));
83  BLI_strncpy(rv->temp_name, name, sizeof(rv->temp_name));
84 
85  strcat(rv->temp_name, temp_ext);
86 
88 
89  rv->fp = BLI_fopen(rv->temp_name, "wb");
90 
91  if (!rv->fp) {
92  fprintf(stderr,
93  "Couldn't open index target: %s! "
94  "Index build broken!\n",
95  rv->temp_name);
96  MEM_freeN(rv);
97  return NULL;
98  }
99 
100  fprintf(rv->fp,
101  "%s%c%.3d",
103  (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v',
105 
106  return rv;
107 }
108 
110  int frameno,
111  uint64_t seek_pos,
112  uint64_t seek_pos_pts,
113  uint64_t seek_pos_dts,
114  uint64_t pts)
115 {
116  fwrite(&frameno, sizeof(int), 1, fp->fp);
117  fwrite(&seek_pos, sizeof(uint64_t), 1, fp->fp);
118  fwrite(&seek_pos_pts, sizeof(uint64_t), 1, fp->fp);
119  fwrite(&seek_pos_dts, sizeof(uint64_t), 1, fp->fp);
120  fwrite(&pts, sizeof(uint64_t), 1, fp->fp);
121 }
122 
124  uchar *buffer,
125  int data_size,
126  int frameno,
127  uint64_t seek_pos,
128  uint64_t seek_pos_pts,
129  uint64_t seek_pos_dts,
130  uint64_t pts)
131 {
132  if (fp->proc_frame) {
134  e.frameno = frameno;
135  e.seek_pos = seek_pos;
136  e.seek_pos_pts = seek_pos_pts;
137  e.seek_pos_dts = seek_pos_dts;
138  e.pts = pts;
139 
140  fp->proc_frame(fp, buffer, data_size, &e);
141  }
142  else {
143  IMB_index_builder_add_entry(fp, frameno, seek_pos, seek_pos_pts, seek_pos_dts, pts);
144  }
145 }
146 
148 {
149  if (fp->delete_priv_data) {
150  fp->delete_priv_data(fp);
151  }
152 
153  fclose(fp->fp);
154 
155  if (rollback) {
156  unlink(fp->temp_name);
157  }
158  else {
159  unlink(fp->name);
160  BLI_rename(fp->temp_name, fp->name);
161  }
162 
163  MEM_freeN(fp);
164 }
165 
166 struct anim_index *IMB_indexer_open(const char *name)
167 {
168  char header[13];
169  struct anim_index *idx;
170  FILE *fp = BLI_fopen(name, "rb");
171  int i;
172 
173  if (!fp) {
174  fprintf(stderr, "Couldn't open indexer file: %s\n", name);
175  return NULL;
176  }
177 
178  if (fread(header, 12, 1, fp) != 1) {
179  fprintf(stderr, "Couldn't read indexer file: %s\n", name);
180  fclose(fp);
181  return NULL;
182  }
183 
184  header[12] = 0;
185 
186  if (memcmp(header, binary_header_str, 8) != 0) {
187  fprintf(stderr, "Error reading %s: Binary file type string missmatch\n", name);
188  fclose(fp);
189  return NULL;
190  }
191 
192  if (atoi(header + 9) != INDEX_FILE_VERSION) {
193  fprintf(stderr, "Error reading %s: File version missmatch\n", name);
194  fclose(fp);
195  return NULL;
196  }
197 
198  idx = MEM_callocN(sizeof(struct anim_index), "anim_index");
199 
200  BLI_strncpy(idx->name, name, sizeof(idx->name));
201 
202  fseek(fp, 0, SEEK_END);
203 
204  idx->num_entries = (ftell(fp) - 12) / (sizeof(int) + /* framepos */
205  sizeof(uint64_t) + /* seek_pos */
206  sizeof(uint64_t) + /* seek_pos_pts */
207  sizeof(uint64_t) + /* seek_pos_dts */
208  sizeof(uint64_t) /* pts */
209  );
210 
211  fseek(fp, 12, SEEK_SET);
212 
213  idx->entries = MEM_callocN(sizeof(struct anim_index_entry) * idx->num_entries,
214  "anim_index_entries");
215 
216  size_t items_read = 0;
217  for (i = 0; i < idx->num_entries; i++) {
218  items_read += fread(&idx->entries[i].frameno, sizeof(int), 1, fp);
219  items_read += fread(&idx->entries[i].seek_pos, sizeof(uint64_t), 1, fp);
220  items_read += fread(&idx->entries[i].seek_pos_pts, sizeof(uint64_t), 1, fp);
221  items_read += fread(&idx->entries[i].seek_pos_dts, sizeof(uint64_t), 1, fp);
222  items_read += fread(&idx->entries[i].pts, sizeof(uint64_t), 1, fp);
223  }
224 
225  if (UNLIKELY(items_read != idx->num_entries * 5)) {
226  fprintf(stderr, "Error: Element data size missmatch in: %s\n", name);
227  MEM_freeN(idx->entries);
228  MEM_freeN(idx);
229  fclose(fp);
230  return NULL;
231  }
232 
233  if (((ENDIAN_ORDER == B_ENDIAN) != (header[8] == 'V'))) {
234  for (i = 0; i < idx->num_entries; i++) {
240  }
241  }
242 
243  fclose(fp);
244 
245  return idx;
246 }
247 
248 uint64_t IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index)
249 {
250  if (frame_index < 0) {
251  frame_index = 0;
252  }
253  if (frame_index >= idx->num_entries) {
254  frame_index = idx->num_entries - 1;
255  }
256  return idx->entries[frame_index].seek_pos;
257 }
258 
259 uint64_t IMB_indexer_get_seek_pos_pts(struct anim_index *idx, int frame_index)
260 {
261  if (frame_index < 0) {
262  frame_index = 0;
263  }
264  if (frame_index >= idx->num_entries) {
265  frame_index = idx->num_entries - 1;
266  }
267  return idx->entries[frame_index].seek_pos_pts;
268 }
269 
270 uint64_t IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index)
271 {
272  if (frame_index < 0) {
273  frame_index = 0;
274  }
275  if (frame_index >= idx->num_entries) {
276  frame_index = idx->num_entries - 1;
277  }
278  return idx->entries[frame_index].seek_pos_dts;
279 }
280 
281 int IMB_indexer_get_frame_index(struct anim_index *idx, int frameno)
282 {
283  int len = idx->num_entries;
284  int half;
285  int middle;
286  int first = 0;
287 
288  /* bsearch (lower bound) the right index */
289 
290  while (len > 0) {
291  half = len >> 1;
292  middle = first;
293 
294  middle += half;
295 
296  if (idx->entries[middle].frameno < frameno) {
297  first = middle;
298  first++;
299  len = len - half - 1;
300  }
301  else {
302  len = half;
303  }
304  }
305 
306  if (first == idx->num_entries) {
307  return idx->num_entries - 1;
308  }
309 
310  return first;
311 }
312 
313 uint64_t IMB_indexer_get_pts(struct anim_index *idx, int frame_index)
314 {
315  if (frame_index < 0) {
316  frame_index = 0;
317  }
318  if (frame_index >= idx->num_entries) {
319  frame_index = idx->num_entries - 1;
320  }
321  return idx->entries[frame_index].pts;
322 }
323 
325 {
326  if (idx->num_entries == 0) {
327  return 0;
328  }
329  return idx->entries[idx->num_entries - 1].frameno + 1;
330 }
331 
332 int IMB_indexer_can_scan(struct anim_index *idx, int old_frame_index, int new_frame_index)
333 {
334  /* makes only sense, if it is the same I-Frame and we are not
335  * trying to run backwards in time... */
336  return (IMB_indexer_get_seek_pos(idx, old_frame_index) ==
337  IMB_indexer_get_seek_pos(idx, new_frame_index) &&
338  old_frame_index < new_frame_index);
339 }
340 
341 void IMB_indexer_close(struct anim_index *idx)
342 {
343  MEM_freeN(idx->entries);
344  MEM_freeN(idx);
345 }
346 
348 {
349  switch (pr_size) {
350  case IMB_PROXY_NONE:
351  return -1;
352  case IMB_PROXY_25:
353  return 0;
354  case IMB_PROXY_50:
355  return 1;
356  case IMB_PROXY_75:
357  return 2;
358  case IMB_PROXY_100:
359  return 3;
360  default:
361  BLI_assert(!"Unhandled proxy size enum!");
362  return -1;
363  }
364 }
365 
367 {
368  switch (tc) {
369  case IMB_TC_NONE:
370  return -1;
371  case IMB_TC_RECORD_RUN:
372  return 0;
373  case IMB_TC_FREE_RUN:
374  return 1;
376  return 2;
378  return 3;
379  default:
380  BLI_assert(!"Unhandled timecode type enum!");
381  return -1;
382  }
383 }
384 
385 /* ----------------------------------------------------------------------
386  * - rebuild helper functions
387  * ---------------------------------------------------------------------- */
388 
389 static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_len)
390 {
391  if (!anim->index_dir[0]) {
392  char fname[FILE_MAXFILE];
393  BLI_split_dirfile(anim->name, index_dir, fname, index_dir_len, sizeof(fname));
394  BLI_path_append(index_dir, index_dir_len, "BL_proxy");
395  BLI_path_append(index_dir, index_dir_len, fname);
396  }
397  else {
398  BLI_strncpy(index_dir, anim->index_dir, index_dir_len);
399  }
400 }
401 
402 void IMB_anim_get_fname(struct anim *anim, char *file, int size)
403 {
404  char fname[FILE_MAXFILE];
405  BLI_split_dirfile(anim->name, file, fname, size, sizeof(fname));
406  BLI_strncpy(file, fname, size);
407 }
408 
409 static bool get_proxy_filename(struct anim *anim,
410  IMB_Proxy_Size preview_size,
411  char *fname,
412  bool temp)
413 {
414  char index_dir[FILE_MAXDIR];
415  int i = IMB_proxy_size_to_array_index(preview_size);
416 
417  BLI_assert(i >= 0);
418 
419  char proxy_name[256];
420  char stream_suffix[20];
421  const char *name = (temp) ? "proxy_%d%s_part.avi" : "proxy_%d%s.avi";
422 
423  stream_suffix[0] = 0;
424 
425  if (anim->streamindex > 0) {
426  BLI_snprintf(stream_suffix, sizeof(stream_suffix), "_st%d", anim->streamindex);
427  }
428 
429  BLI_snprintf(proxy_name,
430  sizeof(proxy_name),
431  name,
432  (int)(proxy_fac[i] * 100),
433  stream_suffix,
434  anim->suffix);
435 
436  get_index_dir(anim, index_dir, sizeof(index_dir));
437 
438  if (BLI_path_ncmp(anim->name, index_dir, FILE_MAXDIR) == 0) {
439  return false;
440  }
441 
442  BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
443  return true;
444 }
445 
446 static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname)
447 {
448  char index_dir[FILE_MAXDIR];
449  int i = IMB_timecode_to_array_index(tc);
450 
451  BLI_assert(i >= 0);
452 
453  const char *index_names[] = {
454  "record_run%s%s.blen_tc",
455  "free_run%s%s.blen_tc",
456  "interp_free_run%s%s.blen_tc",
457  "record_run_no_gaps%s%s.blen_tc",
458  };
459 
460  char stream_suffix[20];
461  char index_name[256];
462 
463  stream_suffix[0] = 0;
464 
465  if (anim->streamindex > 0) {
466  BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
467  }
468 
469  BLI_snprintf(index_name, 256, index_names[i], stream_suffix, anim->suffix);
470 
471  get_index_dir(anim, index_dir, sizeof(index_dir));
472 
473  BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, index_name);
474 }
475 
476 /* ----------------------------------------------------------------------
477  * - common rebuilder structures
478  * ---------------------------------------------------------------------- */
479 
480 typedef struct IndexBuildContext {
483 
484 /* ----------------------------------------------------------------------
485  * - ffmpeg rebuilder
486  * ---------------------------------------------------------------------- */
487 
488 #ifdef WITH_FFMPEG
489 
490 struct proxy_output_ctx {
491  AVFormatContext *of;
492  AVStream *st;
493  AVCodecContext *c;
494  AVCodec *codec;
495  struct SwsContext *sws_ctx;
496  AVFrame *frame;
497  int cfra;
498  int proxy_size;
499  int orig_height;
500  struct anim *anim;
501 };
502 
503 static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
504  struct anim *anim, AVStream *st, int proxy_size, int width, int height, int quality)
505 {
506  struct proxy_output_ctx *rv = MEM_callocN(sizeof(struct proxy_output_ctx), "alloc_proxy_output");
507 
508  char fname[FILE_MAX];
509 
510  rv->proxy_size = proxy_size;
511  rv->anim = anim;
512 
513  get_proxy_filename(rv->anim, rv->proxy_size, fname, true);
514  BLI_make_existing_file(fname);
515 
516  rv->of = avformat_alloc_context();
517  rv->of->oformat = av_guess_format("avi", NULL, NULL);
518 
519  rv->of->url = av_strdup(fname);
520 
521  fprintf(stderr, "Starting work on proxy: %s\n", rv->of->url);
522 
523  rv->st = avformat_new_stream(rv->of, NULL);
524  rv->st->id = 0;
525 
526  rv->c = avcodec_alloc_context3(NULL);
527  rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
528  rv->c->codec_id = AV_CODEC_ID_H264;
529 
530  rv->of->oformat->video_codec = rv->c->codec_id;
531  rv->codec = avcodec_find_encoder(rv->c->codec_id);
532 
533  if (!rv->codec) {
534  fprintf(stderr,
535  "No ffmpeg encoder available? "
536  "Proxy not built!\n");
537  avcodec_free_context(&rv->c);
538  avformat_free_context(rv->of);
539  MEM_freeN(rv);
540  return NULL;
541  }
542 
543  avcodec_get_context_defaults3(rv->c, rv->codec);
544 
545  rv->c->width = width;
546  rv->c->height = height;
547  rv->c->gop_size = 10;
548  rv->c->max_b_frames = 0;
549 
550  if (rv->codec->pix_fmts) {
551  rv->c->pix_fmt = rv->codec->pix_fmts[0];
552  }
553  else {
554  rv->c->pix_fmt = AV_PIX_FMT_YUVJ420P;
555  }
556 
557  rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->sample_aspect_ratio;
558 
559  rv->c->time_base.den = 25;
560  rv->c->time_base.num = 1;
561  rv->st->time_base = rv->c->time_base;
562 
563  /* This range matches eFFMpegCrf. Crf_range_min corresponds to lowest quality, crf_range_max to
564  * highest quality. */
565  const int crf_range_min = 32;
566  const int crf_range_max = 17;
567  int crf = round_fl_to_int((quality / 100.0f) * (crf_range_max - crf_range_min) + crf_range_min);
568 
569  AVDictionary *codec_opts = NULL;
570  /* High quality preset value. */
571  av_dict_set_int(&codec_opts, "crf", crf, 0);
572  /* Prefer smaller file-size. Presets from veryslow to veryfast produce output with very similar
573  * file-size, but there is big difference in performance. In some cases veryfast preset will
574  * produce smallest file-size. */
575  av_dict_set(&codec_opts, "preset", "veryfast", 0);
576  av_dict_set(&codec_opts, "tune", "fastdecode", 0);
577 
578  if (rv->codec->capabilities & AV_CODEC_CAP_AUTO_THREADS) {
579  rv->c->thread_count = 0;
580  }
581  else {
582  rv->c->thread_count = BLI_system_thread_count();
583  }
584 
585  if (rv->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
586  rv->c->thread_type = FF_THREAD_FRAME;
587  }
588  else if (rv->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
589  rv->c->thread_type = FF_THREAD_SLICE;
590  }
591 
592  if (rv->of->flags & AVFMT_GLOBALHEADER) {
593  rv->c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
594  }
595 
596  avcodec_parameters_from_context(rv->st->codecpar, rv->c);
597 
598  int ret = avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE);
599 
600  if (ret < 0) {
601  fprintf(stderr,
602  "Couldn't open IO: %s\n"
603  "Proxy not built!\n",
604  av_err2str(ret));
605  avcodec_free_context(&rv->c);
606  avformat_free_context(rv->of);
607  MEM_freeN(rv);
608  return NULL;
609  }
610 
611  ret = avcodec_open2(rv->c, rv->codec, &codec_opts);
612  if (ret < 0) {
613  fprintf(stderr,
614  "Couldn't open codec: %s\n"
615  "Proxy not built!\n",
616  av_err2str(ret));
617  avcodec_free_context(&rv->c);
618  avformat_free_context(rv->of);
619  MEM_freeN(rv);
620  return NULL;
621  }
622 
623  rv->orig_height = st->codecpar->height;
624 
625  if (st->codecpar->width != width || st->codecpar->height != height ||
626  st->codecpar->format != rv->c->pix_fmt) {
627  rv->frame = av_frame_alloc();
628 
629  av_image_fill_arrays(rv->frame->data,
630  rv->frame->linesize,
631  MEM_mallocN(av_image_get_buffer_size(rv->c->pix_fmt, width, height, 1),
632  "alloc proxy output frame"),
633  rv->c->pix_fmt,
634  width,
635  height,
636  1);
637 
638  rv->frame->format = rv->c->pix_fmt;
639  rv->frame->width = width;
640  rv->frame->height = height;
641 
642  rv->sws_ctx = sws_getContext(st->codecpar->width,
643  rv->orig_height,
644  st->codecpar->format,
645  width,
646  height,
647  rv->c->pix_fmt,
648  SWS_FAST_BILINEAR | SWS_PRINT_INFO,
649  NULL,
650  NULL,
651  NULL);
652  }
653 
654  ret = avformat_write_header(rv->of, NULL);
655  if (ret < 0) {
656  fprintf(stderr,
657  "Couldn't write header: %s\n"
658  "Proxy not built!\n",
659  av_err2str(ret));
660 
661  if (rv->frame) {
662  av_frame_free(&rv->frame);
663  }
664 
665  avcodec_free_context(&rv->c);
666  avformat_free_context(rv->of);
667  MEM_freeN(rv);
668  return NULL;
669  }
670 
671  return rv;
672 }
673 
674 static void add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *frame)
675 {
676  if (!ctx) {
677  return;
678  }
679 
680  if (ctx->sws_ctx && frame &&
681  (frame->data[0] || frame->data[1] || frame->data[2] || frame->data[3])) {
682  sws_scale(ctx->sws_ctx,
683  (const uint8_t *const *)frame->data,
684  frame->linesize,
685  0,
686  ctx->orig_height,
687  ctx->frame->data,
688  ctx->frame->linesize);
689  }
690 
691  frame = ctx->sws_ctx ? (frame ? ctx->frame : 0) : frame;
692 
693  if (frame) {
694  frame->pts = ctx->cfra++;
695  }
696 
697  int ret = avcodec_send_frame(ctx->c, frame);
698  if (ret < 0) {
699  /* Can't send frame to encoder. This shouldn't happen. */
700  fprintf(stderr, "Can't send video frame: %s\n", av_err2str(ret));
701  return;
702  }
703  AVPacket *packet = av_packet_alloc();
704 
705  while (ret >= 0) {
706  ret = avcodec_receive_packet(ctx->c, packet);
707 
708  if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
709  /* No more packets to flush. */
710  break;
711  }
712  if (ret < 0) {
713  fprintf(stderr,
714  "Error encoding proxy frame %d for '%s': %s\n",
715  ctx->cfra - 1,
716  ctx->of->url,
717  av_err2str(ret));
718  break;
719  }
720 
721  packet->stream_index = ctx->st->index;
722  av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base);
723 # ifdef FFMPEG_USE_DURATION_WORKAROUND
724  my_guess_pkt_duration(ctx->of, ctx->st, packet);
725 # endif
726 
727  int write_ret = av_interleaved_write_frame(ctx->of, packet);
728  if (write_ret != 0) {
729  fprintf(stderr,
730  "Error writing proxy frame %d "
731  "into '%s': %s\n",
732  ctx->cfra - 1,
733  ctx->of->url,
734  av_err2str(write_ret));
735  break;
736  }
737  }
738 
739  av_packet_free(&packet);
740 }
741 
742 static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback)
743 {
744  char fname[FILE_MAX];
745  char fname_tmp[FILE_MAX];
746 
747  if (!ctx) {
748  return;
749  }
750 
751  if (!rollback) {
752  /* Flush the remaining packets. */
753  add_to_proxy_output_ffmpeg(ctx, NULL);
754  }
755 
756  avcodec_flush_buffers(ctx->c);
757 
758  av_write_trailer(ctx->of);
759 
760  avcodec_free_context(&ctx->c);
761 
762  if (ctx->of->oformat) {
763  if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
764  avio_close(ctx->of->pb);
765  }
766  }
767  avformat_free_context(ctx->of);
768 
769  if (ctx->sws_ctx) {
770  sws_freeContext(ctx->sws_ctx);
771 
772  MEM_freeN(ctx->frame->data[0]);
773  av_free(ctx->frame);
774  }
775 
776  get_proxy_filename(ctx->anim, ctx->proxy_size, fname_tmp, true);
777 
778  if (rollback) {
779  unlink(fname_tmp);
780  }
781  else {
782  get_proxy_filename(ctx->anim, ctx->proxy_size, fname, false);
783  unlink(fname);
784  BLI_rename(fname_tmp, fname);
785  }
786 
787  MEM_freeN(ctx);
788 }
789 
790 typedef struct FFmpegIndexBuilderContext {
791  int anim_type;
792 
793  AVFormatContext *iFormatCtx;
794  AVCodecContext *iCodecCtx;
795  AVCodec *iCodec;
796  AVStream *iStream;
797  int videoStream;
798 
799  int num_proxy_sizes;
800  int num_indexers;
801 
802  struct proxy_output_ctx *proxy_ctx[IMB_PROXY_MAX_SLOT];
804 
805  IMB_Timecode_Type tcs_in_use;
806  IMB_Proxy_Size proxy_sizes_in_use;
807 
808  uint64_t seek_pos;
809  uint64_t seek_pos_pts;
810  uint64_t seek_pos_dts;
811  uint64_t last_seek_pos;
812  uint64_t last_seek_pos_pts;
813  uint64_t last_seek_pos_dts;
814  uint64_t start_pts;
815  double frame_rate;
816  double pts_time_base;
817  int frameno, frameno_gapless;
818  int start_pts_set;
819 } FFmpegIndexBuilderContext;
820 
821 static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim,
822  IMB_Timecode_Type tcs_in_use,
823  IMB_Proxy_Size proxy_sizes_in_use,
824  int quality)
825 {
826  FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext),
827  "FFmpeg index builder context");
828  int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
829  int num_indexers = IMB_TC_MAX_SLOT;
830  int i, streamcount;
831 
832  context->tcs_in_use = tcs_in_use;
833  context->proxy_sizes_in_use = proxy_sizes_in_use;
834  context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
835  context->num_indexers = IMB_TC_MAX_SLOT;
836 
837  memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
838  memset(context->indexer, 0, sizeof(context->indexer));
839 
840  if (avformat_open_input(&context->iFormatCtx, anim->name, NULL, NULL) != 0) {
842  return NULL;
843  }
844 
845  if (avformat_find_stream_info(context->iFormatCtx, NULL) < 0) {
846  avformat_close_input(&context->iFormatCtx);
848  return NULL;
849  }
850 
851  streamcount = anim->streamindex;
852 
853  /* Find the video stream */
854  context->videoStream = -1;
855  for (i = 0; i < context->iFormatCtx->nb_streams; i++) {
856  if (context->iFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
857  if (streamcount > 0) {
858  streamcount--;
859  continue;
860  }
861  context->videoStream = i;
862  break;
863  }
864  }
865 
866  if (context->videoStream == -1) {
867  avformat_close_input(&context->iFormatCtx);
869  return NULL;
870  }
871 
872  context->iStream = context->iFormatCtx->streams[context->videoStream];
873 
874  context->iCodec = avcodec_find_decoder(context->iStream->codecpar->codec_id);
875 
876  if (context->iCodec == NULL) {
877  avformat_close_input(&context->iFormatCtx);
879  return NULL;
880  }
881 
882  context->iCodecCtx = avcodec_alloc_context3(NULL);
883  avcodec_parameters_to_context(context->iCodecCtx, context->iStream->codecpar);
884  context->iCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
885 
886  if (context->iCodec->capabilities & AV_CODEC_CAP_AUTO_THREADS) {
887  context->iCodecCtx->thread_count = 0;
888  }
889  else {
890  context->iCodecCtx->thread_count = BLI_system_thread_count();
891  }
892 
893  if (context->iCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
894  context->iCodecCtx->thread_type = FF_THREAD_FRAME;
895  }
896  else if (context->iCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
897  context->iCodecCtx->thread_type = FF_THREAD_SLICE;
898  }
899 
900  if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) {
901  avformat_close_input(&context->iFormatCtx);
902  avcodec_free_context(&context->iCodecCtx);
904  return NULL;
905  }
906 
907  for (i = 0; i < num_proxy_sizes; i++) {
908  if (proxy_sizes_in_use & proxy_sizes[i]) {
909  context->proxy_ctx[i] = alloc_proxy_output_ffmpeg(anim,
910  context->iStream,
911  proxy_sizes[i],
912  context->iCodecCtx->width * proxy_fac[i],
913  context->iCodecCtx->height * proxy_fac[i],
914  quality);
915  if (!context->proxy_ctx[i]) {
916  proxy_sizes_in_use &= ~proxy_sizes[i];
917  }
918  }
919  }
920 
921  for (i = 0; i < num_indexers; i++) {
922  if (tcs_in_use & tc_types[i]) {
923  char fname[FILE_MAX];
924 
925  get_tc_filename(anim, tc_types[i], fname);
926 
927  context->indexer[i] = IMB_index_builder_create(fname);
928  if (!context->indexer[i]) {
929  tcs_in_use &= ~tc_types[i];
930  }
931  }
932  }
933 
934  return (IndexBuildContext *)context;
935 }
936 
937 static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int stop)
938 {
939  int i;
940 
941  for (i = 0; i < context->num_indexers; i++) {
942  if (context->tcs_in_use & tc_types[i]) {
943  IMB_index_builder_finish(context->indexer[i], stop);
944  }
945  }
946 
947  for (i = 0; i < context->num_proxy_sizes; i++) {
948  if (context->proxy_sizes_in_use & proxy_sizes[i]) {
949  free_proxy_output_ffmpeg(context->proxy_ctx[i], stop);
950  }
951  }
952 
953  avcodec_free_context(&context->iCodecCtx);
954  avformat_close_input(&context->iFormatCtx);
955 
957 }
958 
959 static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *context,
960  AVPacket *curr_packet,
961  AVFrame *in_frame)
962 {
963  int i;
964  uint64_t s_pos = context->seek_pos;
965  uint64_t s_pts = context->seek_pos_pts;
966  uint64_t s_dts = context->seek_pos_dts;
967  uint64_t pts = av_get_pts_from_frame(in_frame);
968 
969  for (i = 0; i < context->num_proxy_sizes; i++) {
970  add_to_proxy_output_ffmpeg(context->proxy_ctx[i], in_frame);
971  }
972 
973  if (!context->start_pts_set) {
974  context->start_pts = pts;
975  context->start_pts_set = true;
976  }
977 
978  context->frameno = floor(
979  (pts - context->start_pts) * context->pts_time_base * context->frame_rate + 0.5);
980 
981  int64_t seek_pos_pts = timestamp_from_pts_or_dts(context->seek_pos_pts, context->seek_pos_dts);
982 
983  if (pts < seek_pos_pts) {
984  /* Decoding starts *always* on I-Frames. In this case our position is
985  * before our seek I-Frame. So we need to pick the previous available
986  * I-Frame to be able to decode this one properly.
987  */
988  s_pos = context->last_seek_pos;
989  s_pts = context->last_seek_pos_pts;
990  s_dts = context->last_seek_pos_dts;
991  }
992 
993  for (i = 0; i < context->num_indexers; i++) {
994  if (context->tcs_in_use & tc_types[i]) {
995  int tc_frameno = context->frameno;
996 
997  if (tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS) {
998  tc_frameno = context->frameno_gapless;
999  }
1000 
1002  curr_packet->data,
1003  curr_packet->size,
1004  tc_frameno,
1005  s_pos,
1006  s_pts,
1007  s_dts,
1008  pts);
1009  }
1010  }
1011 
1012  context->frameno_gapless++;
1013 }
1014 
1015 static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
1016  const short *stop,
1017  short *do_update,
1018  float *progress)
1019 {
1020  AVFrame *in_frame = av_frame_alloc();
1021  AVPacket *next_packet = av_packet_alloc();
1022  uint64_t stream_size;
1023 
1024  stream_size = avio_size(context->iFormatCtx->pb);
1025 
1026  context->frame_rate = av_q2d(context->iStream->r_frame_rate);
1027  context->pts_time_base = av_q2d(context->iStream->time_base);
1028 
1029  while (av_read_frame(context->iFormatCtx, next_packet) >= 0) {
1030  float next_progress =
1031  (float)((int)floor(((double)next_packet->pos) * 100 / ((double)stream_size) + 0.5)) / 100;
1032 
1033  if (*progress != next_progress) {
1034  *progress = next_progress;
1035  *do_update = true;
1036  }
1037 
1038  if (*stop) {
1039  break;
1040  }
1041 
1042  if (next_packet->stream_index == context->videoStream) {
1043  if (next_packet->flags & AV_PKT_FLAG_KEY) {
1044  context->last_seek_pos = context->seek_pos;
1045  context->last_seek_pos_pts = context->seek_pos_pts;
1046  context->last_seek_pos_dts = context->seek_pos_dts;
1047 
1048  context->seek_pos = next_packet->pos;
1049  context->seek_pos_pts = next_packet->pts;
1050  context->seek_pos_dts = next_packet->dts;
1051  }
1052 
1053  int ret = avcodec_send_packet(context->iCodecCtx, next_packet);
1054  while (ret >= 0) {
1055  ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
1056 
1057  if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
1058  /* No more frames to flush. */
1059  break;
1060  }
1061  if (ret < 0) {
1062  fprintf(stderr, "Error decoding proxy frame: %s\n", av_err2str(ret));
1063  break;
1064  }
1065  index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame);
1066  }
1067  }
1068  av_packet_unref(next_packet);
1069  }
1070 
1071  /* process pictures still stuck in decoder engine after EOF
1072  * according to ffmpeg docs using NULL packets.
1073  *
1074  * At least, if we haven't already stopped... */
1075 
1076  if (!*stop) {
1077  int ret = avcodec_send_packet(context->iCodecCtx, NULL);
1078 
1079  while (ret >= 0) {
1080  ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
1081 
1082  if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
1083  /* No more frames to flush. */
1084  break;
1085  }
1086  if (ret < 0) {
1087  fprintf(stderr, "Error flushing proxy frame: %s\n", av_err2str(ret));
1088  break;
1089  }
1090  index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame);
1091  }
1092  }
1093 
1094  av_packet_free(&next_packet);
1095  av_free(in_frame);
1096 
1097  return 1;
1098 }
1099 
1100 #endif
1101 
1102 /* ----------------------------------------------------------------------
1103  * - internal AVI (fallback) rebuilder
1104  * ---------------------------------------------------------------------- */
1105 
1106 #ifdef WITH_AVI
1107 typedef struct FallbackIndexBuilderContext {
1108  int anim_type;
1109 
1110  struct anim *anim;
1111  AviMovie *proxy_ctx[IMB_PROXY_MAX_SLOT];
1112  IMB_Proxy_Size proxy_sizes_in_use;
1113 } FallbackIndexBuilderContext;
1114 
1115 static AviMovie *alloc_proxy_output_avi(
1116  struct anim *anim, char *filename, int width, int height, int quality)
1117 {
1118  int x, y;
1119  AviFormat format;
1120  double framerate;
1121  AviMovie *avi;
1122  /* it doesn't really matter for proxies, but sane defaults help anyways...*/
1123  short frs_sec = 25;
1124  float frs_sec_base = 1.0;
1125 
1127 
1128  x = width;
1129  y = height;
1130 
1131  framerate = (double)frs_sec / (double)frs_sec_base;
1132 
1133  avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
1134 
1136 
1137  if (AVI_open_compress(filename, avi, 1, format) != AVI_ERROR_NONE) {
1138  MEM_freeN(avi);
1139  return NULL;
1140  }
1141 
1146 
1147  avi->interlace = 0;
1148  avi->odd_fields = 0;
1149 
1150  return avi;
1151 }
1152 
1153 static IndexBuildContext *index_fallback_create_context(struct anim *anim,
1154  IMB_Timecode_Type UNUSED(tcs_in_use),
1155  IMB_Proxy_Size proxy_sizes_in_use,
1156  int quality)
1157 {
1158  FallbackIndexBuilderContext *context;
1159  int i;
1160 
1161  /* since timecode indices only work with ffmpeg right now,
1162  * don't know a sensible fallback here...
1163  *
1164  * so no proxies...
1165  */
1166  if (proxy_sizes_in_use == IMB_PROXY_NONE) {
1167  return NULL;
1168  }
1169 
1170  context = MEM_callocN(sizeof(FallbackIndexBuilderContext), "fallback index builder context");
1171 
1172  context->anim = anim;
1173  context->proxy_sizes_in_use = proxy_sizes_in_use;
1174 
1175  memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
1176 
1177  for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1178  if (context->proxy_sizes_in_use & proxy_sizes[i]) {
1179  char fname[FILE_MAX];
1180 
1181  get_proxy_filename(anim, proxy_sizes[i], fname, true);
1182  BLI_make_existing_file(fname);
1183 
1184  context->proxy_ctx[i] = alloc_proxy_output_avi(
1185  anim, fname, anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality);
1186  }
1187  }
1188 
1189  return (IndexBuildContext *)context;
1190 }
1191 
1192 static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context, int stop)
1193 {
1194  struct anim *anim = context->anim;
1195  char fname[FILE_MAX];
1196  char fname_tmp[FILE_MAX];
1197  int i;
1198 
1199  for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1200  if (context->proxy_sizes_in_use & proxy_sizes[i]) {
1201  AVI_close_compress(context->proxy_ctx[i]);
1202  MEM_freeN(context->proxy_ctx[i]);
1203 
1204  get_proxy_filename(anim, proxy_sizes[i], fname_tmp, true);
1205  get_proxy_filename(anim, proxy_sizes[i], fname, false);
1206 
1207  if (stop) {
1208  unlink(fname_tmp);
1209  }
1210  else {
1211  unlink(fname);
1212  rename(fname_tmp, fname);
1213  }
1214  }
1215  }
1216 }
1217 
1218 static void index_rebuild_fallback(FallbackIndexBuilderContext *context,
1219  const short *stop,
1220  short *do_update,
1221  float *progress)
1222 {
1223  int cnt = IMB_anim_get_duration(context->anim, IMB_TC_NONE);
1224  int i, pos;
1225  struct anim *anim = context->anim;
1226 
1227  for (pos = 0; pos < cnt; pos++) {
1229  struct ImBuf *tmp_ibuf = IMB_dupImBuf(ibuf);
1230  float next_progress = (float)pos / (float)cnt;
1231 
1232  if (*progress != next_progress) {
1233  *progress = next_progress;
1234  *do_update = true;
1235  }
1236 
1237  if (*stop) {
1238  break;
1239  }
1240 
1241  IMB_flipy(tmp_ibuf);
1242 
1243  for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1244  if (context->proxy_sizes_in_use & proxy_sizes[i]) {
1245  int x = anim->x * proxy_fac[i];
1246  int y = anim->y * proxy_fac[i];
1247 
1248  struct ImBuf *s_ibuf = IMB_dupImBuf(tmp_ibuf);
1249 
1250  IMB_scalefastImBuf(s_ibuf, x, y);
1251 
1252  IMB_convert_rgba_to_abgr(s_ibuf);
1253 
1254  AVI_write_frame(context->proxy_ctx[i], pos, AVI_FORMAT_RGB32, s_ibuf->rect, x * y * 4);
1255 
1256  /* note that libavi free's the buffer... */
1257  s_ibuf->rect = NULL;
1258 
1259  IMB_freeImBuf(s_ibuf);
1260  }
1261  }
1262 
1263  IMB_freeImBuf(tmp_ibuf);
1264  IMB_freeImBuf(ibuf);
1265  }
1266 }
1267 
1268 #endif /* WITH_AVI */
1269 
1270 /* ----------------------------------------------------------------------
1271  * - public API
1272  * ---------------------------------------------------------------------- */
1273 
1275  IMB_Timecode_Type tcs_in_use,
1276  IMB_Proxy_Size proxy_sizes_in_use,
1277  int quality,
1278  const bool overwrite,
1279  GSet *file_list)
1280 {
1282  IMB_Proxy_Size proxy_sizes_to_build = proxy_sizes_in_use;
1283  int i;
1284 
1285  /* Don't generate the same file twice! */
1286  if (file_list) {
1287  for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1288  IMB_Proxy_Size proxy_size = proxy_sizes[i];
1289  if (proxy_size & proxy_sizes_to_build) {
1290  char filename[FILE_MAX];
1291  if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
1292  return NULL;
1293  }
1294  void **filename_key_p;
1295  if (!BLI_gset_ensure_p_ex(file_list, filename, &filename_key_p)) {
1296  *filename_key_p = BLI_strdup(filename);
1297  }
1298  else {
1299  proxy_sizes_to_build &= ~proxy_size;
1300  printf("Proxy: %s already registered for generation, skipping\n", filename);
1301  }
1302  }
1303  }
1304  }
1305 
1306  if (!overwrite) {
1308  if (built_proxies != 0) {
1309 
1310  for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1311  IMB_Proxy_Size proxy_size = proxy_sizes[i];
1312  if (proxy_size & built_proxies) {
1313  char filename[FILE_MAX];
1314  if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
1315  return NULL;
1316  }
1317  printf("Skipping proxy: %s\n", filename);
1318  }
1319  }
1320  }
1321  proxy_sizes_to_build &= ~built_proxies;
1322  }
1323 
1324  fflush(stdout);
1325 
1326  if (proxy_sizes_to_build == 0) {
1327  return NULL;
1328  }
1329 
1330  switch (anim->curtype) {
1331 #ifdef WITH_FFMPEG
1332  case ANIM_FFMPEG:
1333  context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
1334  break;
1335 #endif
1336 #ifdef WITH_AVI
1337  default:
1338  context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
1339  break;
1340 #endif
1341  }
1342 
1343  if (context) {
1344  context->anim_type = anim->curtype;
1345  }
1346 
1347  return context;
1348 
1349  UNUSED_VARS(tcs_in_use, proxy_sizes_in_use, quality);
1350 }
1351 
1353  /* NOLINTNEXTLINE: readability-non-const-parameter. */
1354  short *stop,
1355  /* NOLINTNEXTLINE: readability-non-const-parameter. */
1356  short *do_update,
1357  /* NOLINTNEXTLINE: readability-non-const-parameter. */
1358  float *progress)
1359 {
1360  switch (context->anim_type) {
1361 #ifdef WITH_FFMPEG
1362  case ANIM_FFMPEG:
1363  index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
1364  break;
1365 #endif
1366 #ifdef WITH_AVI
1367  default:
1368  index_rebuild_fallback((FallbackIndexBuilderContext *)context, stop, do_update, progress);
1369  break;
1370 #endif
1371  }
1372 
1373  UNUSED_VARS(stop, do_update, progress);
1374 }
1375 
1377 {
1378  switch (context->anim_type) {
1379 #ifdef WITH_FFMPEG
1380  case ANIM_FFMPEG:
1381  index_rebuild_ffmpeg_finish((FFmpegIndexBuilderContext *)context, stop);
1382  break;
1383 #endif
1384 #ifdef WITH_AVI
1385  default:
1386  index_rebuild_fallback_finish((FallbackIndexBuilderContext *)context, stop);
1387  break;
1388 #endif
1389  }
1390 
1391  /* static defined at top of the file */
1392  UNUSED_VARS(stop, proxy_sizes);
1393 }
1394 
1396 {
1397  int i;
1398 
1399  for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1400  if (anim->proxy_anim[i]) {
1402  anim->proxy_anim[i] = NULL;
1403  }
1404  }
1405 
1406  for (i = 0; i < IMB_TC_MAX_SLOT; i++) {
1407  if (anim->curr_idx[i]) {
1409  anim->curr_idx[i] = NULL;
1410  }
1411  }
1412 
1413  anim->proxies_tried = 0;
1414  anim->indices_tried = 0;
1415 }
1416 
1417 void IMB_anim_set_index_dir(struct anim *anim, const char *dir)
1418 {
1419  if (STREQ(anim->index_dir, dir)) {
1420  return;
1421  }
1422  BLI_strncpy(anim->index_dir, dir, sizeof(anim->index_dir));
1423 
1425 }
1426 
1427 struct anim *IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
1428 {
1429  char fname[FILE_MAX];
1430  int i = IMB_proxy_size_to_array_index(preview_size);
1431 
1432  if (i < 0) {
1433  return NULL;
1434  }
1435 
1436  if (anim->proxy_anim[i]) {
1437  return anim->proxy_anim[i];
1438  }
1439 
1440  if (anim->proxies_tried & preview_size) {
1441  return NULL;
1442  }
1443 
1444  get_proxy_filename(anim, preview_size, fname, false);
1445 
1446  /* proxies are generated in the same color space as animation itself */
1447  anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0, anim->colorspace);
1448 
1449  anim->proxies_tried |= preview_size;
1450 
1451  return anim->proxy_anim[i];
1452 }
1453 
1455 {
1456  char fname[FILE_MAX];
1457  int i = IMB_timecode_to_array_index(tc);
1458 
1459  if (i < 0) {
1460  return NULL;
1461  }
1462 
1463  if (anim->curr_idx[i]) {
1464  return anim->curr_idx[i];
1465  }
1466 
1467  if (anim->indices_tried & tc) {
1468  return NULL;
1469  }
1470 
1471  get_tc_filename(anim, tc, fname);
1472 
1473  anim->curr_idx[i] = IMB_indexer_open(fname);
1474 
1475  anim->indices_tried |= tc;
1476 
1477  return anim->curr_idx[i];
1478 }
1479 
1481 {
1482  struct anim_index *idx = IMB_anim_open_index(anim, tc);
1483 
1484  if (!idx) {
1485  return position;
1486  }
1487 
1488  return IMB_indexer_get_frame_index(idx, position);
1489 }
1490 
1492 {
1493  const int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
1494  IMB_Proxy_Size existing = 0;
1495  int i;
1496  for (i = 0; i < num_proxy_sizes; i++) {
1497  IMB_Proxy_Size proxy_size = proxy_sizes[i];
1498  char filename[FILE_MAX];
1499  get_proxy_filename(anim, proxy_size, filename, false);
1500  if (BLI_exists(filename)) {
1501  existing |= proxy_size;
1502  }
1503  }
1504  return existing;
1505 }
@ AVI_ERROR_NONE
Definition: AVI_avi.h:202
AviError AVI_open_compress(char *name, AviMovie *movie, int streams,...)
Definition: avi.c:711
@ AVI_OPTION_HEIGHT
Definition: AVI_avi.h:216
@ AVI_OPTION_FRAMERATE
Definition: AVI_avi.h:218
@ AVI_OPTION_WIDTH
Definition: AVI_avi.h:215
@ AVI_OPTION_QUALITY
Definition: AVI_avi.h:217
AviError AVI_close_compress(AviMovie *movie)
Definition: avi.c:1005
#define AVI_OPTION_TYPE_MAIN
Definition: AVI_avi.h:258
AviFormat
Definition: AVI_avi.h:160
@ AVI_FORMAT_RGB32
Definition: AVI_avi.h:164
@ AVI_FORMAT_MJPEG
Definition: AVI_avi.h:168
AviError AVI_write_frame(AviMovie *movie, int frame_num,...)
Definition: avi.c:897
AviError AVI_set_compress_option(AviMovie *movie, int option_type, int stream, AviOption option, void *opt_data)
Definition: avi_options.c:38
typedef float(TangentPoint)[2]
#define B_ENDIAN
Definition: BKE_global.h:208
#define ENDIAN_ORDER
Definition: BKE_global.h:213
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1)
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1)
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:349
int BLI_rename(const char *from, const char *to) ATTR_NONNULL()
Definition: fileops.c:1381
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
struct GSet GSet
Definition: BLI_ghash.h:189
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
Definition: BLI_ghash.c:1171
MINLINE int round_fl_to_int(float a)
#define BLI_path_ncmp
bool BLI_make_existing_file(const char *name)
Definition: path_util.c:1347
#define FILE_MAXFILE
#define FILE_MAX
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1716
void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1737
void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
Definition: path_util.c:1654
#define FILE_MAXDIR
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:70
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
unsigned char uchar
Definition: BLI_sys_types.h:86
int BLI_system_thread_count(void)
Definition: threads.cc:309
#define UNUSED_VARS(...)
#define UNUSED(x)
#define UNLIKELY(x)
#define STREQ(a, b)
Compatibility-like things for windows.
typedef double(DMatrix)[4][4]
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
#define ANIM_FFMPEG
Definition: IMB_anim.h:79
bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base)
Definition: anim_movie.c:1691
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
IMB_Proxy_Size
Definition: IMB_imbuf.h:317
@ IMB_PROXY_100
Definition: IMB_imbuf.h:322
@ IMB_PROXY_MAX_SLOT
Definition: IMB_imbuf.h:323
@ IMB_PROXY_75
Definition: IMB_imbuf.h:321
@ IMB_PROXY_50
Definition: IMB_imbuf.h:320
@ IMB_PROXY_25
Definition: IMB_imbuf.h:319
@ IMB_PROXY_NONE
Definition: IMB_imbuf.h:318
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
void IMB_close_anim(struct anim *anim)
Definition: anim_movie.c:229
struct anim * IMB_open_anim(const char *name, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
Definition: anim_movie.c:282
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
Definition: imageprocess.c:45
struct ImBuf * IMB_anim_absolute(struct anim *anim, int position, IMB_Timecode_Type tc, IMB_Proxy_Size preview_size)
Definition: anim_movie.c:1580
bool IMB_scalefastImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
Definition: scaling.c:1715
int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
Definition: anim_movie.c:1671
void IMB_flipy(struct ImBuf *ibuf)
Definition: rotate.c:33
IMB_Timecode_Type
Definition: IMB_imbuf.h:298
@ IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN
Definition: IMB_imbuf.h:312
@ IMB_TC_RECORD_RUN_NO_GAPS
Definition: IMB_imbuf.h:313
@ IMB_TC_NONE
Definition: IMB_imbuf.h:300
@ IMB_TC_MAX_SLOT
Definition: IMB_imbuf.h:314
@ IMB_TC_FREE_RUN
Definition: IMB_imbuf.h:307
@ IMB_TC_RECORD_RUN
Definition: IMB_imbuf.h:304
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
Definition: util_half.h:41
FILE * file
FFMPEG_INLINE int64_t timestamp_from_pts_or_dts(int64_t pts, int64_t dts)
Definition: ffmpeg_compat.h:96
FFMPEG_INLINE int64_t av_get_pts_from_frame(AVFrame *picture)
FFMPEG_INLINE void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
Definition: ffmpeg_compat.h:57
uint pos
static bool get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size, char *fname, bool temp)
Definition: indexer.c:409
anim_index_builder * IMB_index_builder_create(const char *name)
Definition: indexer.c:75
void IMB_index_builder_proc_frame(anim_index_builder *fp, uchar *buffer, int data_size, int frameno, uint64_t seek_pos, uint64_t seek_pos_pts, uint64_t seek_pos_dts, uint64_t pts)
Definition: indexer.c:123
void IMB_anim_index_rebuild(struct IndexBuildContext *context, short *stop, short *do_update, float *progress)
Definition: indexer.c:1352
static const char temp_ext[]
Definition: indexer.c:55
uint64_t IMB_indexer_get_seek_pos(struct anim_index *idx, int frame_index)
Definition: indexer.c:248
#define INDEX_FILE_VERSION
Definition: indexer.c:69
static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname)
Definition: indexer.c:446
void IMB_anim_set_index_dir(struct anim *anim, const char *dir)
Definition: indexer.c:1417
uint64_t IMB_indexer_get_seek_pos_pts(struct anim_index *idx, int frame_index)
Definition: indexer.c:259
int IMB_anim_index_get_frame_index(struct anim *anim, IMB_Timecode_Type tc, int position)
Definition: indexer.c:1480
int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
Definition: indexer.c:366
IndexBuildContext * IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecode_Type tcs_in_use, IMB_Proxy_Size proxy_sizes_in_use, int quality, const bool overwrite, GSet *file_list)
Definition: indexer.c:1274
static const char binary_header_str[]
Definition: indexer.c:54
struct anim_index * IMB_anim_open_index(struct anim *anim, IMB_Timecode_Type tc)
Definition: indexer.c:1454
void IMB_index_builder_finish(anim_index_builder *fp, int rollback)
Definition: indexer.c:147
void IMB_indexer_close(struct anim_index *idx)
Definition: indexer.c:341
void IMB_index_builder_add_entry(anim_index_builder *fp, int frameno, uint64_t seek_pos, uint64_t seek_pos_pts, uint64_t seek_pos_dts, uint64_t pts)
Definition: indexer.c:109
uint64_t IMB_indexer_get_seek_pos_dts(struct anim_index *idx, int frame_index)
Definition: indexer.c:270
static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_len)
Definition: indexer.c:389
IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim)
Definition: indexer.c:1491
void IMB_free_indices(struct anim *anim)
Definition: indexer.c:1395
static const float proxy_fac[]
Definition: indexer.c:58
int IMB_indexer_get_duration(struct anim_index *idx)
Definition: indexer.c:324
struct anim * IMB_anim_open_proxy(struct anim *anim, IMB_Proxy_Size preview_size)
Definition: indexer.c:1427
int IMB_indexer_can_scan(struct anim_index *idx, int old_frame_index, int new_frame_index)
Definition: indexer.c:332
uint64_t IMB_indexer_get_pts(struct anim_index *idx, int frame_index)
Definition: indexer.c:313
static const int proxy_sizes[]
Definition: indexer.c:57
struct anim_index * IMB_indexer_open(const char *name)
Definition: indexer.c:166
int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
Definition: indexer.c:347
int IMB_indexer_get_frame_index(struct anim_index *idx, int frameno)
Definition: indexer.c:281
struct IndexBuildContext IndexBuildContext
void IMB_anim_index_rebuild_finish(IndexBuildContext *context, short stop)
Definition: indexer.c:1376
void IMB_anim_get_fname(struct anim *anim, char *file, int size)
Definition: indexer.c:402
unsigned short half
__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_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned c
Definition: RandGen.cpp:97
return ret
struct SELECTID_Context context
Definition: select_engine.c:47
__int64 int64_t
Definition: stdint.h:92
unsigned char uint8_t
Definition: stdint.h:81
unsigned __int64 uint64_t
Definition: stdint.h:93
unsigned int * rect
int odd_fields
Definition: AVI_avi.h:198
int interlace
Definition: AVI_avi.h:197
void(* proc_frame)(struct anim_index_builder *idx, unsigned char *buffer, int data_size, struct anim_index_entry *entry)
Definition: IMB_indexer.h:74
char name[FILE_MAX]
Definition: IMB_indexer.h:68
void(* delete_priv_data)(struct anim_index_builder *idx)
Definition: IMB_indexer.h:73
char temp_name[FILE_MAX]
Definition: IMB_indexer.h:69
Definition: IMB_indexer.h:49
uint64_t pts
Definition: IMB_indexer.h:54
uint64_t seek_pos
Definition: IMB_indexer.h:51
uint64_t seek_pos_pts
Definition: IMB_indexer.h:52
int frameno
Definition: IMB_indexer.h:50
uint64_t seek_pos_dts
Definition: IMB_indexer.h:53
int num_entries
Definition: IMB_indexer.h:60
struct anim_index_entry * entries
Definition: IMB_indexer.h:61
char name[1024]
Definition: IMB_indexer.h:58
Definition: IMB_anim.h:87
int x
Definition: IMB_anim.h:95
struct anim_index * curr_idx[IMB_TC_MAX_SLOT]
Definition: IMB_anim.h:147
struct _AviMovie * avi
Definition: IMB_anim.h:112
int indices_tried
Definition: IMB_anim.h:144
char suffix[64]
Definition: IMB_anim.h:150
char index_dir[768]
Definition: IMB_anim.h:141
int frs_sec
Definition: IMB_anim.h:92
char colorspace[64]
Definition: IMB_anim.h:149
struct anim * proxy_anim[IMB_PROXY_MAX_SLOT]
Definition: IMB_anim.h:146
int y
Definition: IMB_anim.h:95
int proxies_tried
Definition: IMB_anim.h:143
int curtype
Definition: IMB_anim.h:89
int streamindex
Definition: IMB_anim.h:109
char name[1024]
Definition: IMB_anim.h:98
double frs_sec_base
Definition: IMB_anim.h:93
ccl_device_inline float2 floor(const float2 &a)
uint len