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