35# include <libavutil/imgutils.h>
38static const char temp_ext[] =
"_part";
45static const float proxy_fac[] = {0.25, 0.50, 0.75, 1.00};
47#define INDEX_FILE_VERSION 2
55struct MovieIndexBuilder {
61static MovieIndexBuilder *index_builder_create(
const char *filepath)
65 STRNCPY(rv->filepath, filepath);
67 STRNCPY(rv->filepath_temp, filepath);
68 BLI_string_join(rv->filepath_temp,
sizeof(rv->filepath_temp), filepath, temp_ext);
72 rv->fp =
BLI_fopen(rv->filepath_temp,
"wb");
76 "Failed to build index for '%s': could not open '%s' for writing\n",
92static void index_builder_add_entry(
96 fwrite(&frameno,
sizeof(
int), 1, fp->fp);
98 fwrite(&seek_pos_pts,
sizeof(
uint64_t), 1, fp->fp);
99 fwrite(&seek_pos_dts,
sizeof(
uint64_t), 1, fp->fp);
100 fwrite(&pts,
sizeof(
uint64_t), 1, fp->fp);
103static void index_builder_finish(MovieIndexBuilder *fp,
bool rollback)
126 constexpr int64_t header_size = 12;
127 char header[header_size + 1];
128 if (fread(header, header_size, 1, fp) != 1) {
129 fprintf(stderr,
"Couldn't read indexer file: %s\n", filepath);
134 header[header_size] = 0;
137 fprintf(stderr,
"Error reading %s: Binary file type string mismatch\n", filepath);
143 fprintf(stderr,
"Error reading %s: File version mismatch\n", filepath);
148 MovieIndex *idx = MEM_new<MovieIndex>(
"MovieIndex");
152 fseek(fp, 0, SEEK_END);
154 constexpr int64_t entry_size =
sizeof(int) +
160 int64_t num_entries = (ftell(fp) - header_size) / entry_size;
161 fseek(fp, header_size, SEEK_SET);
168 items_read += fread(&idx->
entries[
i].frameno,
sizeof(
int), 1, fp);
169 items_read += fread(&
pad,
sizeof(
uint64_t), 1, fp);
170 items_read += fread(&idx->
entries[
i].seek_pos_pts,
sizeof(
uint64_t), 1, fp);
171 items_read += fread(&idx->
entries[
i].seek_pos_dts,
sizeof(
uint64_t), 1, fp);
175 if (items_read != num_entries * 5) {
176 fprintf(stderr,
"Error: Element data size mismatch in: %s\n", filepath);
199 return this->
entries[frame_index].seek_pos_pts;
205 return this->
entries[frame_index].seek_pos_dts;
216 int middle = first +
half;
218 if (this->
entries[middle].frameno < frameno) {
228 if (first == this->
entries.size()) {
229 return int(this->
entries.size()) - 1;
238 return this->
entries[frame_index].pts;
243 if (this->
entries.is_empty()) {
246 return this->
entries.last().frameno + 1;
301 char stream_suffix[20];
302 const char *name = (temp) ?
"proxy_%d%s_part.avi" :
"proxy_%d%s.avi";
304 stream_suffix[0] = 0;
327 const char *index_names[] = {
328 "record_run%s%s.blen_tc",
329 "record_run_no_gaps%s%s.blen_tc",
332 char stream_suffix[20];
333 char index_name[256];
335 stream_suffix[0] = 0;
354struct proxy_output_ctx {
358 const AVCodec *codec;
367static proxy_output_ctx *alloc_proxy_output_ffmpeg(
MovieReader *anim,
368 AVCodecContext *codec_ctx,
379 rv->proxy_size = proxy_size;
388 rv->of = avformat_alloc_context();
392 rv->of->oformat = av_guess_format(
"mp4",
nullptr,
nullptr);
394 rv->of->url = av_strdup(filepath);
396 rv->st = avformat_new_stream(rv->of,
nullptr);
399 rv->codec = avcodec_find_encoder(AV_CODEC_ID_H264);
401 rv->c = avcodec_alloc_context3(rv->codec);
404 fprintf(stderr,
"Could not build proxy '%s': failed to create video encoder\n", filepath);
405 avcodec_free_context(&rv->c);
406 avformat_free_context(rv->of);
411 rv->c->width = width;
412 rv->c->height = height;
413 rv->c->gop_size = 10;
414 rv->c->max_b_frames = 0;
418 rv->c->pix_fmt = pix_fmts[0];
421 rv->c->pix_fmt = AV_PIX_FMT_YUVJ420P;
424 rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->sample_aspect_ratio;
426 rv->c->time_base.den = 25;
427 rv->c->time_base.num = 1;
428 rv->st->time_base = rv->c->time_base;
429 rv->st->avg_frame_rate = av_inv_q(rv->c->time_base);
433 const int crf_range_min = 32;
434 const int crf_range_max = 17;
435 int crf =
round_fl_to_int((quality / 100.0f) * (crf_range_max - crf_range_min) + crf_range_min);
437 AVDictionary *codec_opts =
nullptr;
439 av_dict_set_int(&codec_opts,
"crf", crf, 0);
443 av_dict_set(&codec_opts,
"preset",
"veryfast", 0);
444 av_dict_set(&codec_opts,
"tune",
"fastdecode", 0);
446 if (rv->codec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
447 rv->c->thread_count = 0;
453 if (rv->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
454 rv->c->thread_type = FF_THREAD_FRAME;
456 else if (rv->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
457 rv->c->thread_type = FF_THREAD_SLICE;
460 if (rv->of->oformat->flags & AVFMT_GLOBALHEADER) {
461 rv->c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
464 rv->c->color_range = codec_ctx->color_range;
465 rv->c->color_primaries = codec_ctx->color_primaries;
466 rv->c->color_trc = codec_ctx->color_trc;
467 rv->c->colorspace = codec_ctx->colorspace;
469 int ret = avio_open(&rv->of->pb, filepath, AVIO_FLAG_WRITE);
472 char error_str[AV_ERROR_MAX_STRING_SIZE];
473 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
476 "Could not build proxy '%s': failed to create output file (%s)\n",
479 avcodec_free_context(&rv->c);
480 avformat_free_context(rv->of);
485 ret = avcodec_open2(rv->c, rv->codec, &codec_opts);
487 char error_str[AV_ERROR_MAX_STRING_SIZE];
488 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
491 "Could not build proxy '%s': failed to open video codec (%s)\n",
494 avcodec_free_context(&rv->c);
495 avformat_free_context(rv->of);
500 avcodec_parameters_from_context(rv->st->codecpar, rv->c);
503 rv->orig_height = st->codecpar->height;
505 if (st->codecpar->width != width || st->codecpar->height != height ||
506 st->codecpar->format != rv->c->pix_fmt)
509 rv->frame = av_frame_alloc();
510 rv->frame->format = rv->c->pix_fmt;
511 rv->frame->width = width;
512 rv->frame->height = height;
513 av_frame_get_buffer(rv->frame, align);
515 rv->sws_ctx = ffmpeg_sws_get_context(st->codecpar->width,
517 AVPixelFormat(st->codecpar->format),
518 codec_ctx->color_range == AVCOL_RANGE_JPEG,
523 codec_ctx->color_range == AVCOL_RANGE_JPEG,
528 ret = avformat_write_header(rv->of,
nullptr);
530 char error_str[AV_ERROR_MAX_STRING_SIZE];
531 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
534 stderr,
"Could not build proxy '%s': failed to write header (%s)\n", filepath, error_str);
537 av_frame_free(&rv->frame);
540 avcodec_free_context(&rv->c);
541 avformat_free_context(rv->of);
549static void add_to_proxy_output_ffmpeg(proxy_output_ctx *ctx, AVFrame *frame)
555 if (ctx->sws_ctx && frame &&
556 (frame->data[0] || frame->data[1] || frame->data[2] || frame->data[3]))
558 ffmpeg_sws_scale_frame(ctx->sws_ctx, ctx->frame, frame);
561 frame = ctx->sws_ctx ? (frame ? ctx->frame :
nullptr) : frame;
564 frame->pts = ctx->cfra++;
567 int ret = avcodec_send_frame(ctx->c, frame);
570 char error_str[AV_ERROR_MAX_STRING_SIZE];
571 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
574 stderr,
"Building proxy '%s': failed to send video frame (%s)\n", ctx->of->url, error_str);
577 AVPacket *packet = av_packet_alloc();
580 ret = avcodec_receive_packet(ctx->c, packet);
582 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
587 char error_str[AV_ERROR_MAX_STRING_SIZE];
588 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
591 "Building proxy '%s': error encoding frame #%i (%s)\n",
598 packet->stream_index = ctx->st->index;
599 av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base);
600# ifdef FFMPEG_USE_DURATION_WORKAROUND
604 int write_ret = av_interleaved_write_frame(ctx->of, packet);
605 if (write_ret != 0) {
606 char error_str[AV_ERROR_MAX_STRING_SIZE];
607 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, write_ret);
610 "Building proxy '%s': error writing frame #%i (%s)\n",
618 av_packet_free(&packet);
621static void free_proxy_output_ffmpeg(proxy_output_ctx *ctx,
int rollback)
632 add_to_proxy_output_ffmpeg(ctx,
nullptr);
635 av_write_trailer(ctx->of);
637 if (ctx->of->oformat) {
638 if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
639 avio_close(ctx->of->pb);
642 avcodec_free_context(&ctx->c);
643 avformat_free_context(ctx->of);
646 ffmpeg_sws_release_context(ctx->sws_ctx);
647 ctx->sws_ctx =
nullptr;
650 av_frame_free(&ctx->frame);
669struct MovieProxyBuilder {
671 AVFormatContext *iFormatCtx;
672 AVCodecContext *iCodecCtx;
673 const AVCodec *iCodec;
683 int proxy_sizes_in_use;
691 double pts_time_base;
692 int frameno, frameno_gapless;
695 bool build_only_on_bad_performance;
696 bool building_cancelled;
699static MovieProxyBuilder *index_ffmpeg_create_context(
MovieReader *anim,
701 int proxy_sizes_in_use,
703 bool build_only_on_bad_performance)
706 if (anim->never_seek_decode_one_frame) {
714 context->tcs_in_use = tcs_in_use;
715 context->proxy_sizes_in_use = proxy_sizes_in_use;
717 context->build_only_on_bad_performance = build_only_on_bad_performance;
722 if (avformat_open_input(&
context->iFormatCtx, anim->
filepath,
nullptr,
nullptr) != 0) {
727 if (avformat_find_stream_info(
context->iFormatCtx,
nullptr) < 0) {
728 avformat_close_input(&
context->iFormatCtx);
737 for (
i = 0;
i <
context->iFormatCtx->nb_streams;
i++) {
738 if (
context->iFormatCtx->streams[
i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
739 if (streamcount > 0) {
748 if (
context->videoStream == -1) {
749 avformat_close_input(&
context->iFormatCtx);
756 context->iCodec = avcodec_find_decoder(
context->iStream->codecpar->codec_id);
758 if (
context->iCodec ==
nullptr) {
759 avformat_close_input(&
context->iFormatCtx);
764 context->iCodecCtx = avcodec_alloc_context3(
nullptr);
765 avcodec_parameters_to_context(
context->iCodecCtx,
context->iStream->codecpar);
766 context->iCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
768 if (
context->iCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
769 context->iCodecCtx->thread_count = 0;
775 if (
context->iCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
776 context->iCodecCtx->thread_type = FF_THREAD_FRAME;
778 else if (
context->iCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
779 context->iCodecCtx->thread_type = FF_THREAD_SLICE;
782 if (avcodec_open2(
context->iCodecCtx,
context->iCodec,
nullptr) < 0) {
783 avformat_close_input(&
context->iFormatCtx);
784 avcodec_free_context(&
context->iCodecCtx);
789 for (
i = 0;
i < num_proxy_sizes;
i++) {
794 height += height % 2;
795 context->proxy_ctx[
i] = alloc_proxy_output_ffmpeg(
803 if (
context->proxy_ctx[0] ==
nullptr &&
context->proxy_ctx[1] ==
nullptr &&
804 context->proxy_ctx[2] ==
nullptr &&
context->proxy_ctx[3] ==
nullptr)
806 avformat_close_input(&
context->iFormatCtx);
807 avcodec_free_context(&
context->iCodecCtx);
813 if (tcs_in_use & tc_types[
i]) {
818 context->indexer[
i] = index_builder_create(filepath);
820 tcs_in_use &= ~int(tc_types[
i]);
828static void index_rebuild_ffmpeg_finish(MovieProxyBuilder *context,
const bool stop)
832 const bool do_rollback =
stop ||
context->building_cancelled;
835 if (
context->tcs_in_use & tc_types[
i]) {
836 index_builder_finish(
context->indexer[
i], do_rollback);
840 for (
i = 0;
i <
context->num_proxy_sizes;
i++) {
842 free_proxy_output_ffmpeg(
context->proxy_ctx[
i], do_rollback);
846 avcodec_free_context(&
context->iCodecCtx);
847 avformat_close_input(&
context->iFormatCtx);
852static void index_rebuild_ffmpeg_proc_decoded_frame(MovieProxyBuilder *context, AVFrame *in_frame)
859 for (
i = 0;
i <
context->num_proxy_sizes;
i++) {
860 add_to_proxy_output_ffmpeg(
context->proxy_ctx[
i], in_frame);
873 if (pts < seek_pos_pts) {
878 s_pts =
context->last_seek_pos_pts;
879 s_dts =
context->last_seek_pos_dts;
883 if (
context->tcs_in_use & tc_types[
i]) {
884 int tc_frameno =
context->frameno;
887 tc_frameno =
context->frameno_gapless;
890 index_builder_add_entry(
context->indexer[
i], tc_frameno, s_pts, s_dts, pts);
897static int index_rebuild_ffmpeg(MovieProxyBuilder *context,
902 AVFrame *in_frame = av_frame_alloc();
903 AVPacket *next_packet = av_packet_alloc();
906 stream_size = avio_size(
context->iFormatCtx->pb);
909 av_guess_frame_rate(
context->iFormatCtx,
context->iStream,
nullptr));
912 while (av_read_frame(
context->iFormatCtx, next_packet) >= 0) {
913 float next_progress =
914 float(
int(
floor(
double(next_packet->pos) * 100 /
double(stream_size) + 0.5))) / 100;
925 if (next_packet->stream_index ==
context->videoStream) {
926 int ret = avcodec_send_packet(
context->iCodecCtx, next_packet);
928 ret = avcodec_receive_frame(
context->iCodecCtx, in_frame);
930 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
935 char error_str[AV_ERROR_MAX_STRING_SIZE];
936 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
937 fprintf(stderr,
"Error decoding proxy frame: %s\n", error_str);
941 if (next_packet->flags & AV_PKT_FLAG_KEY) {
945 context->seek_pos_pts = in_frame->pts;
946 context->seek_pos_dts = in_frame->pkt_dts;
949 index_rebuild_ffmpeg_proc_decoded_frame(context, in_frame);
952 av_packet_unref(next_packet);
961 int ret = avcodec_send_packet(
context->iCodecCtx,
nullptr);
964 ret = avcodec_receive_frame(
context->iCodecCtx, in_frame);
966 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
971 char error_str[AV_ERROR_MAX_STRING_SIZE];
972 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
973 fprintf(stderr,
"Error flushing proxy frame: %s\n", error_str);
976 index_rebuild_ffmpeg_proc_decoded_frame(context, in_frame);
980 av_packet_free(&next_packet);
987static int indexer_performance_get_decode_rate(MovieProxyBuilder *context,
988 const double time_period)
990 AVFrame *in_frame = av_frame_alloc();
991 AVPacket *packet = av_packet_alloc();
994 int frames_decoded = 0;
996 while (av_read_frame(
context->iFormatCtx, packet) >= 0) {
997 if (packet->stream_index !=
context->videoStream) {
998 av_packet_unref(packet);
1002 int ret = avcodec_send_packet(
context->iCodecCtx, packet);
1004 ret = avcodec_receive_frame(
context->iCodecCtx, in_frame);
1006 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
1011 char error_str[AV_ERROR_MAX_STRING_SIZE];
1012 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
1013 fprintf(stderr,
"Error decoding proxy frame: %s\n", error_str);
1021 if (end > start + time_period) {
1024 av_packet_unref(packet);
1027 av_packet_free(&packet);
1028 av_frame_free(&in_frame);
1030 avcodec_flush_buffers(
context->iCodecCtx);
1031 av_seek_frame(
context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1032 return frames_decoded;
1038static int indexer_performance_get_max_gop_size(MovieProxyBuilder *context)
1040 AVPacket *packet = av_packet_alloc();
1042 const int packets_max = 10000;
1043 int packet_index = 0;
1047 while (av_read_frame(
context->iFormatCtx, packet) >= 0) {
1048 if (packet->stream_index !=
context->videoStream) {
1049 av_packet_unref(packet);
1055 if (packet->flags & AV_PKT_FLAG_KEY) {
1056 max_gop =
max_ii(max_gop, cur_gop);
1060 if (packet_index > packets_max) {
1063 av_packet_unref(packet);
1066 av_packet_free(&packet);
1068 av_seek_frame(
context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1079static bool indexer_need_to_build_proxy(MovieProxyBuilder *context)
1081 if (!
context->build_only_on_bad_performance) {
1086 indexer_performance_get_decode_rate(context, 0.1);
1089 const int decode_rate = indexer_performance_get_decode_rate(context, 0.1);
1090 const int max_gop_size = indexer_performance_get_max_gop_size(context);
1092 if (max_gop_size <= 10 || max_gop_size < decode_rate) {
1093 printf(
"Skipping proxy building for %s: Decoding performance is already good.\n",
1095 context->building_cancelled =
true;
1110 int proxy_sizes_in_use,
1112 const bool overwrite,
1114 bool build_only_on_bad_performance)
1116 int proxy_sizes_to_build = proxy_sizes_in_use;
1119 if (processed_paths !=
nullptr) {
1122 if ((proxy_size & proxy_sizes_to_build) == 0) {
1129 if (!processed_paths->
add(filepath)) {
1130 proxy_sizes_to_build &= ~int(proxy_size);
1138 if (built_proxies != 0) {
1141 if (proxy_size & built_proxies) {
1146 printf(
"Skipping proxy: %s\n", filepath);
1150 proxy_sizes_to_build &= ~built_proxies;
1153 if (proxy_sizes_to_build == 0) {
1157 MovieProxyBuilder *context =
nullptr;
1160 context = index_ffmpeg_create_context(
1161 anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
1169 UNUSED_VARS(tcs_in_use, proxy_sizes_in_use, quality);
1181 if (context !=
nullptr) {
1182 if (indexer_need_to_build_proxy(context)) {
1193 if (context !=
nullptr) {
1194 index_rebuild_ffmpeg_finish(context,
stop);
1203 if (anim ==
nullptr) {
1280 if (index ==
nullptr) {
1308 for (
int i = 0;
i < num_proxy_sizes;
i++) {
1313 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_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
int BLI_rename_overwrite(const char *from, const char *to) ATTR_NONNULL()
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
MINLINE int round_fl_to_int(float a)
MINLINE int max_ii(int a, int b)
#define BLI_path_join(...)
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
#define SNPRINTF(dst, format,...)
char * STRNCPY(char(&dst)[N], const char *src)
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)
const char * dirname(char *path)
Read Guarded memory(de)allocation.
@ IMB_TC_RECORD_RUN_NO_GAPS
int pad[32 - sizeof(int)]
unsigned long long int uint64_t
void resize(const int64_t new_size)
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 enum AVPixelFormat * ffmpeg_get_pix_fmts(struct AVCodecContext *context, const AVCodec *codec)
FFMPEG_INLINE void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
FFMPEG_INLINE void ffmpeg_copy_display_matrix(const AVStream *src, AVStream *dst)
void * MEM_callocN(size_t len, const char *str)
void MEM_freeN(void *vmemh)
void MOV_set_custom_proxy_dir(MovieReader *anim, const char *dir)
MovieProxyBuilder * MOV_proxy_builder_start(MovieReader *anim, IMB_Timecode_Type tcs_in_use, int proxy_sizes_in_use, int quality, const bool overwrite, blender::Set< std::string > *processed_paths, bool build_only_on_bad_performance)
void MOV_proxy_builder_process(MovieProxyBuilder *context, bool *stop, bool *do_update, float *progress)
#define INDEX_FILE_VERSION
const MovieIndex * movie_open_index(MovieReader *anim, IMB_Timecode_Type tc)
static const IMB_Proxy_Size proxy_sizes[]
static int proxy_size_to_array_index(IMB_Proxy_Size pr_size)
static const char binary_header_str[]
void MOV_close_proxies(MovieReader *anim)
static const float proxy_fac[]
static MovieIndex * movie_index_open(const char *filepath)
static void get_tc_filepath(MovieReader *anim, IMB_Timecode_Type tc, char *filepath)
int MOV_get_existing_proxies(const MovieReader *anim)
int MOV_calc_frame_index_with_timecode(MovieReader *anim, IMB_Timecode_Type tc, int position)
static void movie_index_free(MovieIndex *idx)
void MOV_proxy_builder_finish(MovieProxyBuilder *context, const bool stop)
static void get_index_dir(const MovieReader *anim, char *index_dir, size_t index_dir_maxncpy)
MovieReader * movie_open_proxy(MovieReader *anim, IMB_Proxy_Size preview_size)
static bool get_proxy_filepath(const MovieReader *anim, IMB_Proxy_Size preview_size, char *filepath, bool temp)
void MOV_close(MovieReader *anim)
MovieReader * MOV_open_file(const char *filepath, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
int context(const bContext *C, const char *member, bContextDataResult *result)
T clamp(const T &a, const T &min, const T &max)
blender::Vector< MovieIndexFrame > entries
int get_frame_index(int frameno) const
uint64_t get_seek_pos_dts(int frame_index) const
uint64_t get_pts(int frame_index) const
uint64_t get_seek_pos_pts(int frame_index) const
MovieReader * proxy_anim[IMB_PROXY_MAX_SLOT]