40# include <libavutil/imgutils.h>
43static const char temp_ext[] =
"_part";
50static const float proxy_fac[] = {0.25, 0.50, 0.75, 1.00};
52#define INDEX_FILE_VERSION 2
60struct MovieIndexBuilder {
66static MovieIndexBuilder *index_builder_create(
const char *filepath)
70 STRNCPY(rv->filepath, filepath);
72 STRNCPY(rv->filepath_temp, filepath);
73 BLI_string_join(rv->filepath_temp,
sizeof(rv->filepath_temp), filepath, temp_ext);
77 rv->fp =
BLI_fopen(rv->filepath_temp,
"wb");
81 "Failed to build index for '%s': could not open '%s' for writing",
99static void index_builder_add_entry(
103 fwrite(&frameno,
sizeof(
int), 1, fp->fp);
105 fwrite(&seek_pos_pts,
sizeof(
uint64_t), 1, fp->fp);
106 fwrite(&seek_pos_dts,
sizeof(
uint64_t), 1, fp->fp);
107 fwrite(&pts,
sizeof(
uint64_t), 1, fp->fp);
110static void index_builder_finish(MovieIndexBuilder *fp,
bool rollback)
133 constexpr int64_t header_size = 12;
134 char header[header_size + 1];
135 if (fread(header, header_size, 1, fp) != 1) {
136 CLOG_ERROR(&
LOG,
"Couldn't read indexer file: %s", filepath);
141 header[header_size] = 0;
144 CLOG_ERROR(&
LOG,
"Error reading %s: Binary file type string mismatch", filepath);
150 CLOG_ERROR(&
LOG,
"Error reading %s: File version mismatch", filepath);
155 MovieIndex *idx = MEM_new<MovieIndex>(
"MovieIndex");
159 fseek(fp, 0, SEEK_END);
161 constexpr int64_t entry_size =
sizeof(int) +
167 int64_t num_entries = (ftell(fp) - header_size) / entry_size;
168 fseek(fp, header_size, SEEK_SET);
175 items_read += fread(&idx->
entries[
i].frameno,
sizeof(
int), 1, fp);
176 items_read += fread(&
pad,
sizeof(
uint64_t), 1, fp);
177 items_read += fread(&idx->
entries[
i].seek_pos_pts,
sizeof(
uint64_t), 1, fp);
178 items_read += fread(&idx->
entries[
i].seek_pos_dts,
sizeof(
uint64_t), 1, fp);
182 if (items_read != num_entries * 5) {
183 CLOG_ERROR(&
LOG,
"Error: Element data size mismatch in: %s", filepath);
209 return this->
entries[frame_index].seek_pos_pts;
215 return this->
entries[frame_index].seek_pos_dts;
226 int middle = first +
half;
228 if (this->
entries[middle].frameno < frameno) {
238 if (first == this->
entries.size()) {
239 return int(this->
entries.size()) - 1;
248 return this->
entries[frame_index].pts;
253 if (this->
entries.is_empty()) {
256 return this->
entries.last().frameno + 1;
311 char stream_suffix[20];
312 const char *
name = (temp) ?
"proxy_%d%s_part.avi" :
"proxy_%d%s.avi";
314 stream_suffix[0] = 0;
337 const char *index_names[] = {
338 "record_run%s%s.blen_tc",
339 "record_run_no_gaps%s%s.blen_tc",
342 char stream_suffix[20];
343 char index_name[256];
345 stream_suffix[0] = 0;
364struct proxy_output_ctx {
368 const AVCodec *codec;
377static proxy_output_ctx *alloc_proxy_output_ffmpeg(
MovieReader *anim,
378 AVCodecContext *codec_ctx,
389 rv->proxy_size = proxy_size;
398 rv->of = avformat_alloc_context();
402 rv->of->oformat = av_guess_format(
"mp4",
nullptr,
nullptr);
404 rv->of->url = av_strdup(filepath);
406 rv->st = avformat_new_stream(rv->of,
nullptr);
409 rv->codec = avcodec_find_encoder(AV_CODEC_ID_H264);
411 rv->c = avcodec_alloc_context3(rv->codec);
414 CLOG_ERROR(&
LOG,
"Could not build proxy '%s': failed to create video encoder", filepath);
415 avcodec_free_context(&rv->c);
416 avformat_free_context(rv->of);
421 rv->c->width = width;
422 rv->c->height = height;
423 rv->c->gop_size = 10;
424 rv->c->max_b_frames = 0;
428 rv->c->pix_fmt = pix_fmts[0];
431 rv->c->pix_fmt = AV_PIX_FMT_YUVJ420P;
434 rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->sample_aspect_ratio;
436 rv->c->time_base.den = 25;
437 rv->c->time_base.num = 1;
438 rv->st->time_base = rv->c->time_base;
439 rv->st->avg_frame_rate = av_inv_q(rv->c->time_base);
443 const int crf_range_min = 32;
444 const int crf_range_max = 17;
445 int crf =
round_fl_to_int((quality / 100.0f) * (crf_range_max - crf_range_min) + crf_range_min);
447 AVDictionary *codec_opts =
nullptr;
449 av_dict_set_int(&codec_opts,
"crf", crf, 0);
453 av_dict_set(&codec_opts,
"preset",
"veryfast", 0);
454 av_dict_set(&codec_opts,
"tune",
"fastdecode", 0);
456 if (rv->codec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
457 rv->c->thread_count = 0;
460 rv->c->thread_count = MOV_thread_count();
463 if (rv->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
464 rv->c->thread_type = FF_THREAD_FRAME;
466 else if (rv->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
467 rv->c->thread_type = FF_THREAD_SLICE;
470 if (rv->of->oformat->flags & AVFMT_GLOBALHEADER) {
471 rv->c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
474 rv->c->color_range = codec_ctx->color_range;
475 rv->c->color_primaries = codec_ctx->color_primaries;
476 rv->c->color_trc = codec_ctx->color_trc;
477 rv->c->colorspace = codec_ctx->colorspace;
479 int ret = avio_open(&rv->of->pb, filepath, AVIO_FLAG_WRITE);
482 char error_str[AV_ERROR_MAX_STRING_SIZE];
483 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
486 "Could not build proxy '%s': failed to create output file (%s)",
489 avcodec_free_context(&rv->c);
490 avformat_free_context(rv->of);
495 ret = avcodec_open2(rv->c, rv->codec, &codec_opts);
497 char error_str[AV_ERROR_MAX_STRING_SIZE];
498 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
501 &
LOG,
"Could not build proxy '%s': failed to open video codec (%s)", filepath, error_str);
502 avcodec_free_context(&rv->c);
503 avformat_free_context(rv->of);
508 avcodec_parameters_from_context(rv->st->codecpar, rv->c);
511 rv->orig_height = st->codecpar->height;
513 if (st->codecpar->width != width || st->codecpar->height != height ||
514 st->codecpar->format != rv->c->pix_fmt)
517 rv->frame = av_frame_alloc();
518 rv->frame->format = rv->c->pix_fmt;
519 rv->frame->width = width;
520 rv->frame->height = height;
521 av_frame_get_buffer(rv->frame, align);
523 rv->sws_ctx = ffmpeg_sws_get_context(st->codecpar->width,
525 AVPixelFormat(st->codecpar->format),
526 codec_ctx->color_range == AVCOL_RANGE_JPEG,
531 codec_ctx->color_range == AVCOL_RANGE_JPEG,
536 ret = avformat_write_header(rv->of,
nullptr);
538 char error_str[AV_ERROR_MAX_STRING_SIZE];
539 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
542 &
LOG,
"Could not build proxy '%s': failed to write header (%s)", filepath, error_str);
545 av_frame_free(&rv->frame);
548 avcodec_free_context(&rv->c);
549 avformat_free_context(rv->of);
557static void add_to_proxy_output_ffmpeg(proxy_output_ctx *ctx, AVFrame *frame)
563 if (ctx->sws_ctx && frame &&
564 (frame->data[0] || frame->data[1] || frame->data[2] || frame->data[3]))
566 ffmpeg_sws_scale_frame(ctx->sws_ctx, ctx->frame, frame);
569 frame = ctx->sws_ctx ? (frame ? ctx->frame :
nullptr) : frame;
572 frame->pts = ctx->cfra++;
575 int ret = avcodec_send_frame(ctx->c, frame);
578 char error_str[AV_ERROR_MAX_STRING_SIZE];
579 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
582 &
LOG,
"Building proxy '%s': failed to send video frame (%s)", ctx->of->url, error_str);
585 AVPacket *packet = av_packet_alloc();
588 ret = avcodec_receive_packet(ctx->c, packet);
590 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
595 char error_str[AV_ERROR_MAX_STRING_SIZE];
596 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
599 "Building proxy '%s': error encoding frame #%i (%s)",
606 packet->stream_index = ctx->st->index;
607 av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base);
608# ifdef FFMPEG_USE_DURATION_WORKAROUND
612 int write_ret = av_interleaved_write_frame(ctx->of, packet);
613 if (write_ret != 0) {
614 char error_str[AV_ERROR_MAX_STRING_SIZE];
615 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, write_ret);
618 "Building proxy '%s': error writing frame #%i (%s)",
626 av_packet_free(&packet);
629static void free_proxy_output_ffmpeg(proxy_output_ctx *ctx,
int rollback)
640 add_to_proxy_output_ffmpeg(ctx,
nullptr);
643 av_write_trailer(ctx->of);
645 if (ctx->of->oformat) {
646 if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
647 avio_close(ctx->of->pb);
650 avcodec_free_context(&ctx->c);
651 avformat_free_context(ctx->of);
654 ffmpeg_sws_release_context(ctx->sws_ctx);
655 ctx->sws_ctx =
nullptr;
658 av_frame_free(&ctx->frame);
677struct MovieProxyBuilder {
679 AVFormatContext *iFormatCtx;
680 AVCodecContext *iCodecCtx;
681 const AVCodec *iCodec;
691 int proxy_sizes_in_use;
699 double pts_time_base;
700 int frameno, frameno_gapless;
703 bool build_only_on_bad_performance;
704 bool building_cancelled;
707static MovieProxyBuilder *index_ffmpeg_create_context(
MovieReader *anim,
709 int proxy_sizes_in_use,
711 bool build_only_on_bad_performance)
714 if (anim->never_seek_decode_one_frame) {
722 context->tcs_in_use = tcs_in_use;
723 context->proxy_sizes_in_use = proxy_sizes_in_use;
725 context->build_only_on_bad_performance = build_only_on_bad_performance;
730 if (avformat_open_input(&
context->iFormatCtx, anim->
filepath,
nullptr,
nullptr) != 0) {
735 if (avformat_find_stream_info(
context->iFormatCtx,
nullptr) < 0) {
736 avformat_close_input(&
context->iFormatCtx);
745 for (
i = 0;
i <
context->iFormatCtx->nb_streams;
i++) {
746 if (
context->iFormatCtx->streams[
i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
747 if (streamcount > 0) {
756 if (
context->videoStream == -1) {
757 avformat_close_input(&
context->iFormatCtx);
764 context->iCodec = avcodec_find_decoder(
context->iStream->codecpar->codec_id);
766 if (
context->iCodec ==
nullptr) {
767 avformat_close_input(&
context->iFormatCtx);
772 context->iCodecCtx = avcodec_alloc_context3(
nullptr);
773 avcodec_parameters_to_context(
context->iCodecCtx,
context->iStream->codecpar);
774 context->iCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
776 if (
context->iCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
777 context->iCodecCtx->thread_count = 0;
780 context->iCodecCtx->thread_count = MOV_thread_count();
783 if (
context->iCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
784 context->iCodecCtx->thread_type = FF_THREAD_FRAME;
786 else if (
context->iCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
787 context->iCodecCtx->thread_type = FF_THREAD_SLICE;
790 if (avcodec_open2(
context->iCodecCtx,
context->iCodec,
nullptr) < 0) {
791 avformat_close_input(&
context->iFormatCtx);
792 avcodec_free_context(&
context->iCodecCtx);
797 for (
i = 0;
i < num_proxy_sizes;
i++) {
802 height += height % 2;
803 context->proxy_ctx[
i] = alloc_proxy_output_ffmpeg(
811 if (
context->proxy_ctx[0] ==
nullptr &&
context->proxy_ctx[1] ==
nullptr &&
812 context->proxy_ctx[2] ==
nullptr &&
context->proxy_ctx[3] ==
nullptr)
814 avformat_close_input(&
context->iFormatCtx);
815 avcodec_free_context(&
context->iCodecCtx);
821 if (tcs_in_use & tc_types[
i]) {
826 context->indexer[
i] = index_builder_create(filepath);
828 tcs_in_use &= ~int(tc_types[
i]);
836static void index_rebuild_ffmpeg_finish(MovieProxyBuilder *context,
const bool stop)
840 const bool do_rollback = stop ||
context->building_cancelled;
843 if (
context->tcs_in_use & tc_types[
i]) {
844 index_builder_finish(
context->indexer[
i], do_rollback);
848 for (
i = 0;
i <
context->num_proxy_sizes;
i++) {
850 free_proxy_output_ffmpeg(
context->proxy_ctx[
i], do_rollback);
854 avcodec_free_context(&
context->iCodecCtx);
855 avformat_close_input(&
context->iFormatCtx);
860static void index_rebuild_ffmpeg_proc_decoded_frame(MovieProxyBuilder *context, AVFrame *in_frame)
867 for (
i = 0;
i <
context->num_proxy_sizes;
i++) {
868 add_to_proxy_output_ffmpeg(
context->proxy_ctx[
i], in_frame);
881 if (pts < seek_pos_pts) {
886 s_pts =
context->last_seek_pos_pts;
887 s_dts =
context->last_seek_pos_dts;
891 if (
context->tcs_in_use & tc_types[
i]) {
892 int tc_frameno =
context->frameno;
895 tc_frameno =
context->frameno_gapless;
898 index_builder_add_entry(
context->indexer[
i], tc_frameno, s_pts, s_dts, pts);
905static int index_rebuild_ffmpeg(MovieProxyBuilder *context,
910 AVFrame *in_frame = av_frame_alloc();
911 AVPacket *next_packet = av_packet_alloc();
914 stream_size = avio_size(
context->iFormatCtx->pb);
917 av_guess_frame_rate(
context->iFormatCtx,
context->iStream,
nullptr));
920 while (av_read_frame(
context->iFormatCtx, next_packet) >= 0) {
921 float next_progress =
922 float(
int(
floor(
double(next_packet->pos) * 100 /
double(stream_size) + 0.5))) / 100;
924 if (*progress != next_progress) {
925 *progress = next_progress;
933 if (next_packet->stream_index ==
context->videoStream) {
934 int ret = avcodec_send_packet(
context->iCodecCtx, next_packet);
936 ret = avcodec_receive_frame(
context->iCodecCtx, in_frame);
938 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
943 char error_str[AV_ERROR_MAX_STRING_SIZE];
944 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
945 CLOG_ERROR(&
LOG,
"Error decoding proxy frame: %s", error_str);
949 if (next_packet->flags & AV_PKT_FLAG_KEY) {
953 context->seek_pos_pts = in_frame->pts;
954 context->seek_pos_dts = in_frame->pkt_dts;
957 index_rebuild_ffmpeg_proc_decoded_frame(context, in_frame);
960 av_packet_unref(next_packet);
969 int ret = avcodec_send_packet(
context->iCodecCtx,
nullptr);
972 ret = avcodec_receive_frame(
context->iCodecCtx, in_frame);
974 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
979 char error_str[AV_ERROR_MAX_STRING_SIZE];
980 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
981 CLOG_ERROR(&
LOG,
"Error flushing proxy frame: %s", error_str);
984 index_rebuild_ffmpeg_proc_decoded_frame(context, in_frame);
988 av_packet_free(&next_packet);
995static int indexer_performance_get_decode_rate(MovieProxyBuilder *context,
996 const double time_period)
998 AVFrame *in_frame = av_frame_alloc();
999 AVPacket *packet = av_packet_alloc();
1002 int frames_decoded = 0;
1004 while (av_read_frame(
context->iFormatCtx, packet) >= 0) {
1005 if (packet->stream_index !=
context->videoStream) {
1006 av_packet_unref(packet);
1010 int ret = avcodec_send_packet(
context->iCodecCtx, packet);
1012 ret = avcodec_receive_frame(
context->iCodecCtx, in_frame);
1014 if (
ret == AVERROR(EAGAIN) ||
ret == AVERROR_EOF) {
1019 char error_str[AV_ERROR_MAX_STRING_SIZE];
1020 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE,
ret);
1021 CLOG_ERROR(&
LOG,
"Error decoding proxy frame: %s", error_str);
1029 if (end > start + time_period) {
1032 av_packet_unref(packet);
1035 av_packet_free(&packet);
1036 av_frame_free(&in_frame);
1038 avcodec_flush_buffers(
context->iCodecCtx);
1039 av_seek_frame(
context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1040 return frames_decoded;
1046static int indexer_performance_get_max_gop_size(MovieProxyBuilder *context)
1048 AVPacket *packet = av_packet_alloc();
1050 const int packets_max = 10000;
1051 int packet_index = 0;
1055 while (av_read_frame(
context->iFormatCtx, packet) >= 0) {
1056 if (packet->stream_index !=
context->videoStream) {
1057 av_packet_unref(packet);
1063 if (packet->flags & AV_PKT_FLAG_KEY) {
1064 max_gop =
max_ii(max_gop, cur_gop);
1068 if (packet_index > packets_max) {
1071 av_packet_unref(packet);
1074 av_packet_free(&packet);
1076 av_seek_frame(
context->iFormatCtx, -1, 0, AVSEEK_FLAG_BACKWARD);
1087static bool indexer_need_to_build_proxy(MovieProxyBuilder *context)
1089 if (!
context->build_only_on_bad_performance) {
1094 indexer_performance_get_decode_rate(context, 0.1);
1097 const int decode_rate = indexer_performance_get_decode_rate(context, 0.1);
1098 const int max_gop_size = indexer_performance_get_max_gop_size(context);
1100 if (max_gop_size <= 10 || max_gop_size < decode_rate) {
1102 "Skipping proxy building for %s: Decoding performance is already good.",
1104 context->building_cancelled =
true;
1119 int proxy_sizes_in_use,
1121 const bool overwrite,
1123 bool build_only_on_bad_performance)
1125 int proxy_sizes_to_build = proxy_sizes_in_use;
1128 if (processed_paths !=
nullptr) {
1131 if ((proxy_size & proxy_sizes_to_build) == 0) {
1138 if (!processed_paths->
add(filepath)) {
1139 proxy_sizes_to_build &= ~int(proxy_size);
1147 if (built_proxies != 0) {
1150 if (proxy_size & built_proxies) {
1159 proxy_sizes_to_build &= ~built_proxies;
1162 if (proxy_sizes_to_build == 0) {
1166 MovieProxyBuilder *context =
nullptr;
1169 context = index_ffmpeg_create_context(
1170 anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
1178 UNUSED_VARS(tcs_in_use, proxy_sizes_in_use, quality);
1190 if (context !=
nullptr) {
1191 if (indexer_need_to_build_proxy(context)) {
1192 index_rebuild_ffmpeg(context, stop, do_update, progress);
1202 if (context !=
nullptr) {
1203 index_rebuild_ffmpeg_finish(context, stop);
1212 if (anim ==
nullptr) {
1292 if (index ==
nullptr) {
1320 for (
int i = 0;
i < num_proxy_sizes;
i++) {
1325 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(...)
Platform independent time functions.
double BLI_time_now_seconds(void)
const char * dirname(char *path)
#define CLOG_ERROR(clg_ref,...)
#define CLOG_INFO_NOCHECK(clg_ref, format,...)
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, const int ib_flags, const int streamindex, const bool keep_original_colorspace, 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]