40# include <libavutil/imgutils.h>
49static const float proxy_fac[] = {0.25, 0.50, 0.75, 1.00};
51#define INDEX_FILE_VERSION 2
62 fprintf(stderr,
"Starting work on index: %s\n", filepath);
75 "Couldn't open index target: %s! "
76 "Index build broken!\n",
98 fwrite(&frameno,
sizeof(
int), 1, fp->
fp);
99 fwrite(&seek_pos,
sizeof(
uint64_t), 1, fp->
fp);
100 fwrite(&seek_pos_pts,
sizeof(
uint64_t), 1, fp->
fp);
101 fwrite(&seek_pos_dts,
sizeof(
uint64_t), 1, fp->
fp);
117 e.seek_pos = seek_pos;
118 e.seek_pos_pts = seek_pos_pts;
119 e.seek_pos_dts = seek_pos_dts;
159 if (fread(header, 12, 1, fp) != 1) {
160 fprintf(stderr,
"Couldn't read indexer file: %s\n", filepath);
168 fprintf(stderr,
"Error reading %s: Binary file type string mismatch\n", filepath);
174 fprintf(stderr,
"Error reading %s: File version mismatch\n", filepath);
179 idx = MEM_cnew<ImBufAnimIndex>(
"ImBufAnimIndex");
183 fseek(fp, 0, SEEK_END);
185 idx->
num_entries = (ftell(fp) - 12) / (
sizeof(
int) +
192 fseek(fp, 12, SEEK_SET);
197 size_t items_read = 0;
199 items_read += fread(&idx->
entries[i].
frameno,
sizeof(
int), 1, fp);
207 fprintf(stderr,
"Error: Element data size mismatch in: %s\n", filepath);
233 if (frame_index <= 0) {
244 if (frame_index < 0) {
255 if (frame_index < 0) {
298 if (frame_index < 0) {
321 old_frame_index < new_frame_index);
396 char proxy_name[256];
397 char stream_suffix[20];
398 const char *name = (temp) ?
"proxy_%d%s_part.avi" :
"proxy_%d%s.avi";
400 stream_suffix[0] = 0;
425 const char *index_names[] = {
426 "record_run%s%s.blen_tc",
427 "record_run_no_gaps%s%s.blen_tc",
430 char stream_suffix[20];
431 char index_name[256];
433 stream_suffix[0] = 0;
439 SNPRINTF(index_name, index_names[i], stream_suffix, anim->
suffix);
458struct proxy_output_ctx {
462 const AVCodec *codec;
471static proxy_output_ctx *alloc_proxy_output_ffmpeg(
474 proxy_output_ctx *rv = MEM_cnew<proxy_output_ctx>(
"alloc_proxy_output");
478 rv->proxy_size = proxy_size;
487 rv->of = avformat_alloc_context();
488 rv->of->oformat = av_guess_format(
"avi",
nullptr,
nullptr);
490 rv->of->url = av_strdup(filepath);
492 fprintf(stderr,
"Starting work on proxy: %s\n", rv->of->url);
494 rv->st = avformat_new_stream(rv->of,
nullptr);
497 rv->codec = avcodec_find_encoder(AV_CODEC_ID_H264);
499 rv->c = avcodec_alloc_context3(rv->codec);
503 "No ffmpeg encoder available? "
504 "Proxy not built!\n");
505 avcodec_free_context(&rv->c);
506 avformat_free_context(rv->of);
511 rv->c->width = width;
512 rv->c->height = height;
513 rv->c->gop_size = 10;
514 rv->c->max_b_frames = 0;
516 if (rv->codec->pix_fmts) {
517 rv->c->pix_fmt = rv->codec->pix_fmts[0];
520 rv->c->pix_fmt = AV_PIX_FMT_YUVJ420P;
523 rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->sample_aspect_ratio;
525 rv->c->time_base.den = 25;
526 rv->c->time_base.num = 1;
527 rv->st->time_base = rv->c->time_base;
531 const int crf_range_min = 32;
532 const int crf_range_max = 17;
533 int crf =
round_fl_to_int((quality / 100.0f) * (crf_range_max - crf_range_min) + crf_range_min);
535 AVDictionary *codec_opts =
nullptr;
537 av_dict_set_int(&codec_opts,
"crf", crf, 0);
541 av_dict_set(&codec_opts,
"preset",
"veryfast", 0);
542 av_dict_set(&codec_opts,
"tune",
"fastdecode", 0);
544 if (rv->codec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
545 rv->c->thread_count = 0;
551 if (rv->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
552 rv->c->thread_type = FF_THREAD_FRAME;
554 else if (rv->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
555 rv->c->thread_type = FF_THREAD_SLICE;
558 if (rv->of->flags & AVFMT_GLOBALHEADER) {
559 rv->c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
562 avcodec_parameters_from_context(rv->st->codecpar, rv->c);
564 int ret = avio_open(&rv->of->pb, filepath, AVIO_FLAG_WRITE);
567 char error_str[AV_ERROR_MAX_STRING_SIZE];
568 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
571 "Couldn't open IO: %s\n"
572 "Proxy not built!\n",
574 avcodec_free_context(&rv->c);
575 avformat_free_context(rv->of);
580 ret = avcodec_open2(rv->c, rv->codec, &codec_opts);
582 char error_str[AV_ERROR_MAX_STRING_SIZE];
583 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
586 "Couldn't open codec: %s\n"
587 "Proxy not built!\n",
589 avcodec_free_context(&rv->c);
590 avformat_free_context(rv->of);
595 rv->orig_height = st->codecpar->height;
597 if (st->codecpar->width != width || st->codecpar->height != height ||
598 st->codecpar->format != rv->c->pix_fmt)
601 rv->frame = av_frame_alloc();
602 rv->frame->format = rv->c->pix_fmt;
603 rv->frame->width = width;
604 rv->frame->height = height;
605 av_frame_get_buffer(rv->frame, align);
607 rv->sws_ctx = BKE_ffmpeg_sws_get_context(st->codecpar->width,
609 AVPixelFormat(st->codecpar->format),
616 ret = avformat_write_header(rv->of,
nullptr);
618 char error_str[AV_ERROR_MAX_STRING_SIZE];
619 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
622 "Couldn't write header: %s\n"
623 "Proxy not built!\n",
627 av_frame_free(&rv->frame);
630 avcodec_free_context(&rv->c);
631 avformat_free_context(rv->of);
639static void add_to_proxy_output_ffmpeg(proxy_output_ctx *ctx, AVFrame *frame)
645 if (ctx->sws_ctx && frame &&
646 (frame->data[0] || frame->data[1] || frame->data[2] || frame->data[3]))
648 BKE_ffmpeg_sws_scale_frame(ctx->sws_ctx, ctx->frame, frame);
651 frame = ctx->sws_ctx ? (frame ? ctx->frame :
nullptr) : frame;
654 frame->pts = ctx->cfra++;
657 int ret = avcodec_send_frame(ctx->c, frame);
660 char error_str[AV_ERROR_MAX_STRING_SIZE];
661 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
663 fprintf(stderr,
"Can't send video frame: %s\n", error_str);
666 AVPacket *packet = av_packet_alloc();
669 ret = avcodec_receive_packet(ctx->c, packet);
671 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
676 char error_str[AV_ERROR_MAX_STRING_SIZE];
677 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
680 "Error encoding proxy frame %d for '%s': %s\n",
687 packet->stream_index = ctx->st->index;
688 av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base);
689# ifdef FFMPEG_USE_DURATION_WORKAROUND
693 int write_ret = av_interleaved_write_frame(ctx->of, packet);
694 if (write_ret != 0) {
695 char error_str[AV_ERROR_MAX_STRING_SIZE];
696 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, write_ret);
699 "Error writing proxy frame %d "
708 av_packet_free(&packet);
711static void free_proxy_output_ffmpeg(proxy_output_ctx *ctx,
int rollback)
722 add_to_proxy_output_ffmpeg(ctx,
nullptr);
725 avcodec_flush_buffers(ctx->c);
727 av_write_trailer(ctx->of);
729 avcodec_free_context(&ctx->c);
731 if (ctx->of->oformat) {
732 if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
733 avio_close(ctx->of->pb);
736 avformat_free_context(ctx->of);
739 BKE_ffmpeg_sws_release_context(ctx->sws_ctx);
740 ctx->sws_ctx =
nullptr;
743 av_frame_free(&ctx->frame);
749 unlink(filepath_tmp);
764 AVFormatContext *iFormatCtx;
765 AVCodecContext *iCodecCtx;
766 const AVCodec *iCodec;
776 int proxy_sizes_in_use;
786 double pts_time_base;
787 int frameno, frameno_gapless;
790 bool build_only_on_bad_performance;
791 bool building_cancelled;
796 int proxy_sizes_in_use,
798 bool build_only_on_bad_performance)
800 FFmpegIndexBuilderContext *context = MEM_cnew<FFmpegIndexBuilderContext>(
801 "FFmpeg index builder context");
805 context->tcs_in_use = tcs_in_use;
806 context->proxy_sizes_in_use = proxy_sizes_in_use;
808 context->build_only_on_bad_performance = build_only_on_bad_performance;
810 memset(context->proxy_ctx, 0,
sizeof(context->proxy_ctx));
811 memset(context->indexer, 0,
sizeof(context->indexer));
813 if (avformat_open_input(&context->iFormatCtx, anim->
filepath,
nullptr,
nullptr) != 0) {
818 if (avformat_find_stream_info(context->iFormatCtx,
nullptr) < 0) {
819 avformat_close_input(&context->iFormatCtx);
827 context->videoStream = -1;
828 for (i = 0; i < context->iFormatCtx->nb_streams; i++) {
829 if (context->iFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
830 if (streamcount > 0) {
834 context->videoStream = i;
839 if (context->videoStream == -1) {
840 avformat_close_input(&context->iFormatCtx);
845 context->iStream = context->iFormatCtx->streams[context->videoStream];
847 context->iCodec = avcodec_find_decoder(context->iStream->codecpar->codec_id);
849 if (context->iCodec ==
nullptr) {
850 avformat_close_input(&context->iFormatCtx);
855 context->iCodecCtx = avcodec_alloc_context3(
nullptr);
856 avcodec_parameters_to_context(context->iCodecCtx, context->iStream->codecpar);
857 context->iCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
859 if (context->iCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
860 context->iCodecCtx->thread_count = 0;
866 if (context->iCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
867 context->iCodecCtx->thread_type = FF_THREAD_FRAME;
869 else if (context->iCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
870 context->iCodecCtx->thread_type = FF_THREAD_SLICE;
873 if (avcodec_open2(context->iCodecCtx, context->iCodec,
nullptr) < 0) {
874 avformat_close_input(&context->iFormatCtx);
875 avcodec_free_context(&context->iCodecCtx);
880 for (i = 0; i < num_proxy_sizes; i++) {
882 int width = context->iCodecCtx->width *
proxy_fac[i];
883 int height = context->iCodecCtx->height *
proxy_fac[i];
885 height += height % 2;
886 context->proxy_ctx[i] = alloc_proxy_output_ffmpeg(
887 anim, context->iStream,
proxy_sizes[i], width, height, quality);
888 if (!context->proxy_ctx[i]) {
894 if (context->proxy_ctx[0] ==
nullptr && context->proxy_ctx[1] ==
nullptr &&
895 context->proxy_ctx[2] ==
nullptr && context->proxy_ctx[3] ==
nullptr)
897 avformat_close_input(&context->iFormatCtx);
898 avcodec_free_context(&context->iCodecCtx);
903 for (i = 0; i < tc_types.size(); i++) {
904 if (tcs_in_use & tc_types[i]) {
910 if (!context->indexer[i]) {
911 tcs_in_use &= ~int(tc_types[i]);
919static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context,
const bool stop)
923 const bool do_rollback = stop || context->building_cancelled;
925 for (i = 0; i < tc_types.size(); i++) {
926 if (context->tcs_in_use & tc_types[i]) {
931 for (i = 0; i < context->num_proxy_sizes; i++) {
932 if (context->proxy_sizes_in_use &
proxy_sizes[i]) {
933 free_proxy_output_ffmpeg(context->proxy_ctx[i], do_rollback);
937 avcodec_free_context(&context->iCodecCtx);
938 avformat_close_input(&context->iFormatCtx);
943static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *context,
944 AVPacket *curr_packet,
949 uint64_t s_pts = context->seek_pos_pts;
950 uint64_t s_dts = context->seek_pos_dts;
953 for (i = 0; i < context->num_proxy_sizes; i++) {
954 add_to_proxy_output_ffmpeg(context->proxy_ctx[i], in_frame);
957 if (!context->start_pts_set) {
958 context->start_pts = pts;
959 context->start_pts_set =
true;
962 context->frameno =
floor(
963 (pts - context->start_pts) * context->pts_time_base * context->frame_rate + 0.5);
967 if (pts < seek_pos_pts) {
972 s_pos = context->last_seek_pos;
973 s_pts = context->last_seek_pos_pts;
974 s_dts = context->last_seek_pos_dts;
977 for (i = 0; i < tc_types.size(); i++) {
978 if (context->tcs_in_use & tc_types[i]) {
979 int tc_frameno = context->frameno;
982 tc_frameno = context->frameno_gapless;
996 context->frameno_gapless++;
999static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
1004 AVFrame *in_frame = av_frame_alloc();
1005 AVPacket *next_packet = av_packet_alloc();
1008 stream_size = avio_size(context->iFormatCtx->pb);
1010 context->frame_rate = av_q2d(
1011 av_guess_frame_rate(context->iFormatCtx, context->iStream,
nullptr));
1012 context->pts_time_base = av_q2d(context->iStream->time_base);
1014 while (av_read_frame(context->iFormatCtx, next_packet) >= 0) {
1015 float next_progress =
1016 float(
int(
floor(
double(next_packet->pos) * 100 /
double(stream_size) + 0.5))) / 100;
1018 if (*progress != next_progress) {
1019 *progress = next_progress;
1027 if (next_packet->stream_index == context->videoStream) {
1028 int ret = avcodec_send_packet(context->iCodecCtx, next_packet);
1030 ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
1032 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
1037 char error_str[AV_ERROR_MAX_STRING_SIZE];
1038 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
1039 fprintf(stderr,
"Error decoding proxy frame: %s\n", error_str);
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;
1048 context->seek_pos = in_frame->pkt_pos;
1049 context->seek_pos_pts = in_frame->pts;
1050 context->seek_pos_dts = in_frame->pkt_dts;
1053 index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame);
1056 av_packet_unref(next_packet);
1065 int ret = avcodec_send_packet(context->iCodecCtx,
nullptr);
1068 ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
1070 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
1075 char error_str[AV_ERROR_MAX_STRING_SIZE];
1076 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
1077 fprintf(stderr,
"Error flushing proxy frame: %s\n", error_str);
1080 index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame);
1084 av_packet_free(&next_packet);
1091static int indexer_performance_get_decode_rate(FFmpegIndexBuilderContext *context,
1092 const double time_period)
1094 AVFrame *in_frame = av_frame_alloc();
1095 AVPacket *packet = av_packet_alloc();
1098 int frames_decoded = 0;
1100 while (av_read_frame(context->iFormatCtx, packet) >= 0) {
1101 if (packet->stream_index != context->videoStream) {
1102 av_packet_unref(packet);
1106 int ret = avcodec_send_packet(context->iCodecCtx, packet);
1108 ret = avcodec_receive_frame(context->iCodecCtx, in_frame);
1110 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
1115 char error_str[AV_ERROR_MAX_STRING_SIZE];
1116 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
1117 fprintf(stderr,
"Error decoding proxy frame: %s\n", error_str);
1125 if (end > start + time_period) {
1128 av_packet_unref(packet);
1131 av_packet_free(&packet);
1132 av_frame_free(&in_frame);
1134 avcodec_flush_buffers(context->iCodecCtx);
1135 av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1136 return frames_decoded;
1142static int indexer_performance_get_max_gop_size(FFmpegIndexBuilderContext *context)
1144 AVPacket *packet = av_packet_alloc();
1146 const int packets_max = 10000;
1147 int packet_index = 0;
1151 while (av_read_frame(context->iFormatCtx, packet) >= 0) {
1152 if (packet->stream_index != context->videoStream) {
1153 av_packet_unref(packet);
1159 if (packet->flags & AV_PKT_FLAG_KEY) {
1160 max_gop =
max_ii(max_gop, cur_gop);
1164 if (packet_index > packets_max) {
1167 av_packet_unref(packet);
1170 av_packet_free(&packet);
1172 av_seek_frame(context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1183static bool indexer_need_to_build_proxy(FFmpegIndexBuilderContext *context)
1185 if (!context->build_only_on_bad_performance) {
1190 indexer_performance_get_decode_rate(context, 0.1);
1193 const int decode_rate = indexer_performance_get_decode_rate(context, 0.1);
1194 const int max_gop_size = indexer_performance_get_max_gop_size(context);
1196 if (max_gop_size <= 10 || max_gop_size < decode_rate) {
1197 printf(
"Skipping proxy building for %s: Decoding performance is already good.\n",
1198 context->iFormatCtx->url);
1199 context->building_cancelled =
true;
1214 int proxy_sizes_in_use,
1216 const bool overwrite,
1218 bool build_only_on_bad_performance)
1220 int proxy_sizes_to_build = proxy_sizes_in_use;
1227 if (proxy_size & proxy_sizes_to_build) {
1232 void **filepath_key_p;
1237 proxy_sizes_to_build &= ~int(proxy_size);
1238 printf(
"Proxy: %s already registered for generation, skipping\n", filepath);
1246 if (built_proxies != 0) {
1250 if (proxy_size & built_proxies) {
1255 printf(
"Skipping proxy: %s\n", filepath);
1259 proxy_sizes_to_build &= ~built_proxies;
1264 if (proxy_sizes_to_build == 0) {
1271 context = index_ffmpeg_create_context(
1272 anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
1280 UNUSED_VARS(tcs_in_use, proxy_sizes_in_use, quality);
1292 if (context !=
nullptr) {
1293 if (indexer_need_to_build_proxy((FFmpegIndexBuilderContext *)context)) {
1294 index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
1304 if (context !=
nullptr) {
1305 index_rebuild_ffmpeg_finish((FFmpegIndexBuilderContext *)context, stop);
1389 if (index ==
nullptr) {
1418 for (i = 0; i < num_proxy_sizes; i++) {
1423 existing |=
int(proxy_size);
#define BLI_assert_msg(a, msg)
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()
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_rename(const char *from, const char *to) ATTR_NONNULL()
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
MINLINE int round_fl_to_int(float a)
MINLINE int max_ii(int a, int b)
#define BLI_path_join(...)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
#define STRNCPY(dst, src)
#define SNPRINTF(dst, format,...)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define BLI_string_join(...)
int BLI_system_thread_count(void)
Platform independent time functions.
double BLI_time_now_seconds(void)
Compatibility-like things for windows.
const char * dirname(char *path)
ImBufAnim * IMB_open_anim(const char *filepath, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
void IMB_close_anim(ImBufAnim *anim)
@ IMB_TC_RECORD_RUN_NO_GAPS
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
FFMPEG_INLINE size_t ffmpeg_get_buffer_alignment()
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)
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)
static bool get_proxy_filepath(ImBufAnim *anim, IMB_Proxy_Size preview_size, char *filepath, bool temp)
void IMB_anim_index_rebuild(IndexBuildContext *context, bool *stop, bool *do_update, float *progress)
static const char temp_ext[]
uint64_t IMB_indexer_get_seek_pos(ImBufAnimIndex *idx, int frame_index)
void IMB_indexer_close(ImBufAnimIndex *idx)
#define INDEX_FILE_VERSION
anim_index_builder * IMB_index_builder_create(const char *filepath)
int IMB_indexer_get_frame_index(ImBufAnimIndex *idx, int frameno)
void IMB_anim_set_index_dir(ImBufAnim *anim, const char *dir)
int IMB_anim_index_get_frame_index(ImBufAnim *anim, IMB_Timecode_Type tc, int position)
static void get_tc_filepath(ImBufAnim *anim, IMB_Timecode_Type tc, char *filepath)
int IMB_indexer_get_duration(ImBufAnimIndex *idx)
ImBufAnimIndex * IMB_anim_open_index(ImBufAnim *anim, IMB_Timecode_Type tc)
int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
uint64_t IMB_indexer_get_seek_pos_pts(ImBufAnimIndex *idx, int frame_index)
ImBufAnim * IMB_anim_open_proxy(ImBufAnim *anim, IMB_Proxy_Size preview_size)
uint64_t IMB_indexer_get_seek_pos_dts(ImBufAnimIndex *idx, int frame_index)
static const IMB_Proxy_Size proxy_sizes[]
void IMB_anim_index_rebuild_finish(IndexBuildContext *context, const bool stop)
static const char binary_header_str[]
uint64_t IMB_indexer_get_pts(ImBufAnimIndex *idx, int frame_index)
void IMB_index_builder_finish(anim_index_builder *fp, int rollback)
int IMB_anim_proxy_get_existing(ImBufAnim *anim)
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)
static void get_index_dir(ImBufAnim *anim, char *index_dir, size_t index_dir_maxncpy)
static const float proxy_fac[]
IndexBuildContext * IMB_anim_index_rebuild_context(ImBufAnim *anim, IMB_Timecode_Type tcs_in_use, int proxy_sizes_in_use, int quality, const bool overwrite, GSet *file_list, bool build_only_on_bad_performance)
int IMB_indexer_can_scan(ImBufAnimIndex *idx, int old_frame_index, int new_frame_index)
void IMB_anim_get_filename(ImBufAnim *anim, char *filename, int filename_maxncpy)
int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
ImBufAnimIndex * IMB_indexer_open(const char *filepath)
void IMB_free_indices(ImBufAnim *anim)
void MEM_freeN(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
ccl_device_inline float2 floor(const float2 a)
unsigned __int64 uint64_t
anim_index_entry * entries
ImBufAnimIndex * record_run
ImBufAnim * proxy_anim[IMB_PROXY_MAX_SLOT]
void(* proc_frame)(anim_index_builder *idx, unsigned char *buffer, int data_size, anim_index_entry *entry)
char filepath_temp[FILE_MAX]
void(* delete_priv_data)(anim_index_builder *idx)