2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Peter Schlaile <peter [at] schlaile [dot] de> 2011
20 * Contributor(s): none yet.
22 * ***** END GPL LICENSE BLOCK *****
25 /** \file blender/imbuf/intern/indexer.c
31 #include "MEM_guardedalloc.h"
33 #include "BLI_utildefines.h"
34 #include "BLI_endian_switch.h"
35 #include "BLI_path_util.h"
36 #include "BLI_string.h"
37 #include "BLI_path_util.h"
38 #include "BLI_fileops.h"
39 #include "BLI_math_base.h"
41 #include "IMB_indexer.h"
45 #include "MEM_guardedalloc.h"
46 #include "DNA_userdef_types.h"
47 #include "BKE_global.h"
54 # include "ffmpeg_compat.h"
58 static const char magic[] = "BlenMIdx";
59 static const char temp_ext[] = "_part";
61 static const int proxy_sizes[] = { IMB_PROXY_25, IMB_PROXY_50, IMB_PROXY_75,
63 static const float proxy_fac[] = { 0.25, 0.50, 0.75, 1.00 };
66 static int tc_types[] = {IMB_TC_RECORD_RUN,
68 IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN,
69 IMB_TC_RECORD_RUN_NO_GAPS};
72 #define INDEX_FILE_VERSION 1
74 /* ----------------------------------------------------------------------
75 * - time code index functions
76 * ---------------------------------------------------------------------- */
78 anim_index_builder *IMB_index_builder_create(const char *name)
81 anim_index_builder *rv = MEM_callocN(sizeof(struct anim_index_builder),
84 fprintf(stderr, "Starting work on index: %s\n", name);
86 BLI_strncpy(rv->name, name, sizeof(rv->name));
87 BLI_strncpy(rv->temp_name, name, sizeof(rv->temp_name));
89 strcat(rv->temp_name, temp_ext);
91 BLI_make_existing_file(rv->temp_name);
93 rv->fp = BLI_fopen(rv->temp_name, "wb");
96 fprintf(stderr, "Couldn't open index target: %s! "
97 "Index build broken!\n", rv->temp_name);
102 fprintf(rv->fp, "%s%c%.3d", magic, (ENDIAN_ORDER == B_ENDIAN) ? 'V' : 'v',
108 void IMB_index_builder_add_entry(anim_index_builder *fp,
109 int frameno, unsigned long long seek_pos,
110 unsigned long long seek_pos_dts,
111 unsigned long long pts)
113 fwrite(&frameno, sizeof(int), 1, fp->fp);
114 fwrite(&seek_pos, sizeof(unsigned long long), 1, fp->fp);
115 fwrite(&seek_pos_dts, sizeof(unsigned long long), 1, fp->fp);
116 fwrite(&pts, sizeof(unsigned long long), 1, fp->fp);
119 void IMB_index_builder_proc_frame(anim_index_builder *fp,
120 unsigned char *buffer,
122 int frameno, unsigned long long seek_pos,
123 unsigned long long seek_pos_dts,
124 unsigned long long pts)
126 if (fp->proc_frame) {
129 e.seek_pos = seek_pos;
130 e.seek_pos_dts = seek_pos_dts;
133 fp->proc_frame(fp, buffer, data_size, &e);
136 IMB_index_builder_add_entry(fp, frameno, seek_pos,
141 void IMB_index_builder_finish(anim_index_builder *fp, int rollback)
143 if (fp->delete_priv_data) {
144 fp->delete_priv_data(fp);
150 unlink(fp->temp_name);
154 BLI_rename(fp->temp_name, fp->name);
160 struct anim_index *IMB_indexer_open(const char *name)
163 struct anim_index *idx;
164 FILE *fp = BLI_fopen(name, "rb");
171 if (fread(header, 12, 1, fp) != 1) {
178 if (memcmp(header, magic, 8) != 0) {
183 if (atoi(header + 9) != INDEX_FILE_VERSION) {
188 idx = MEM_callocN(sizeof(struct anim_index), "anim_index");
190 BLI_strncpy(idx->name, name, sizeof(idx->name));
192 fseek(fp, 0, SEEK_END);
194 idx->num_entries = (ftell(fp) - 12) /
195 (sizeof(int) + /* framepos */
196 sizeof(unsigned long long) + /* seek_pos */
197 sizeof(unsigned long long) + /* seek_pos_dts */
198 sizeof(unsigned long long) /* pts */
201 fseek(fp, 12, SEEK_SET);
203 idx->entries = MEM_callocN(sizeof(struct anim_index_entry) *
204 idx->num_entries, "anim_index_entries");
206 for (i = 0; i < idx->num_entries; i++) {
207 fread(&idx->entries[i].frameno,
209 fread(&idx->entries[i].seek_pos,
210 sizeof(unsigned long long), 1, fp);
211 fread(&idx->entries[i].seek_pos_dts,
212 sizeof(unsigned long long), 1, fp);
213 fread(&idx->entries[i].pts,
214 sizeof(unsigned long long), 1, fp);
217 if (((ENDIAN_ORDER == B_ENDIAN) != (header[8] == 'V'))) {
218 for (i = 0; i < idx->num_entries; i++) {
219 BLI_endian_switch_int32(&idx->entries[i].frameno);
220 BLI_endian_switch_int64((int64_t *)&idx->entries[i].seek_pos);
221 BLI_endian_switch_int64((int64_t *)&idx->entries[i].seek_pos_dts);
222 BLI_endian_switch_int64((int64_t *)&idx->entries[i].pts);
231 unsigned long long IMB_indexer_get_seek_pos(
232 struct anim_index *idx, int frame_index)
234 if (frame_index < 0) {
237 if (frame_index >= idx->num_entries) {
238 frame_index = idx->num_entries - 1;
240 return idx->entries[frame_index].seek_pos;
243 unsigned long long IMB_indexer_get_seek_pos_dts(
244 struct anim_index *idx, int frame_index)
246 if (frame_index < 0) {
249 if (frame_index >= idx->num_entries) {
250 frame_index = idx->num_entries - 1;
252 return idx->entries[frame_index].seek_pos_dts;
255 int IMB_indexer_get_frame_index(struct anim_index *idx, int frameno)
257 int len = idx->num_entries;
262 /* bsearch (lower bound) the right index */
270 if (idx->entries[middle].frameno < frameno) {
273 len = len - half - 1;
280 if (first == idx->num_entries) {
281 return idx->num_entries - 1;
288 unsigned long long IMB_indexer_get_pts(struct anim_index *idx,
291 if (frame_index < 0) {
294 if (frame_index >= idx->num_entries) {
295 frame_index = idx->num_entries - 1;
297 return idx->entries[frame_index].pts;
300 int IMB_indexer_get_duration(struct anim_index *idx)
302 if (idx->num_entries == 0) {
305 return idx->entries[idx->num_entries - 1].frameno + 1;
308 int IMB_indexer_can_scan(struct anim_index *idx,
309 int old_frame_index, int new_frame_index)
311 /* makes only sense, if it is the same I-Frame and we are not
312 * trying to run backwards in time... */
313 return (IMB_indexer_get_seek_pos(idx, old_frame_index) == IMB_indexer_get_seek_pos(idx, new_frame_index) &&
314 old_frame_index < new_frame_index);
317 void IMB_indexer_close(struct anim_index *idx)
319 MEM_freeN(idx->entries);
323 int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
326 case IMB_PROXY_NONE: /* if we got here, something is broken anyways,
327 * so sane defaults... */
343 int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
346 case IMB_TC_NONE: /* if we got here, something is broken anyways,
347 * so sane defaults... */
349 case IMB_TC_RECORD_RUN:
351 case IMB_TC_FREE_RUN:
353 case IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN:
355 case IMB_TC_RECORD_RUN_NO_GAPS:
364 /* ----------------------------------------------------------------------
365 * - rebuild helper functions
366 * ---------------------------------------------------------------------- */
368 static void get_index_dir(struct anim *anim, char *index_dir, size_t index_dir_len)
370 if (!anim->index_dir[0]) {
371 char fname[FILE_MAXFILE];
372 BLI_split_dirfile(anim->name, index_dir, fname, index_dir_len, sizeof(fname));
373 BLI_path_append(index_dir, index_dir_len, "BL_proxy");
374 BLI_path_append(index_dir, index_dir_len, fname);
377 BLI_strncpy(index_dir, anim->index_dir, index_dir_len);
381 static void get_proxy_filename(struct anim *anim, IMB_Proxy_Size preview_size,
382 char *fname, int temp)
384 char index_dir[FILE_MAXDIR];
385 int i = IMB_proxy_size_to_array_index(preview_size);
387 char proxy_name[256];
388 char proxy_temp_name[256];
389 char stream_suffix[20];
391 stream_suffix[0] = 0;
393 if (anim->streamindex > 0) {
394 BLI_snprintf(stream_suffix, sizeof(stream_suffix), "_st%d", anim->streamindex);
397 BLI_snprintf(proxy_name, sizeof(proxy_name), "proxy_%d%s.avi",
398 (int) (proxy_fac[i] * 100), stream_suffix);
399 BLI_snprintf(proxy_temp_name, sizeof(proxy_temp_name), "proxy_%d%s_part.avi",
400 (int) (proxy_fac[i] * 100), stream_suffix);
402 get_index_dir(anim, index_dir, sizeof(index_dir));
404 BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir,
405 temp ? proxy_temp_name : proxy_name);
408 static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc,
411 char index_dir[FILE_MAXDIR];
412 int i = IMB_timecode_to_array_index(tc);
413 const char *index_names[] = {
414 "record_run%s.blen_tc",
415 "free_run%s.blen_tc",
416 "interp_free_run%s.blen_tc",
417 "record_run_no_gaps%s.blen_tc"
420 char stream_suffix[20];
421 char index_name[256];
423 stream_suffix[0] = 0;
425 if (anim->streamindex > 0) {
426 BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
429 BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
431 get_index_dir(anim, index_dir, sizeof(index_dir));
433 BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR,
434 index_dir, index_name);
437 /* ----------------------------------------------------------------------
438 * - common rebuilder structures
439 * ---------------------------------------------------------------------- */
441 typedef struct IndexBuildContext {
446 /* ----------------------------------------------------------------------
448 * ---------------------------------------------------------------------- */
452 struct proxy_output_ctx {
457 struct SwsContext *sws_ctx;
465 // work around stupid swscaler 16 bytes alignment bug...
467 static int round_up(int x, int mod)
469 return x + ((mod - (x % mod)) % mod);
472 static struct proxy_output_ctx *alloc_proxy_output_ffmpeg(
474 AVStream *st, int proxy_size, int width, int height,
477 struct proxy_output_ctx *rv = MEM_callocN(
478 sizeof(struct proxy_output_ctx), "alloc_proxy_output");
480 char fname[FILE_MAX];
483 /* JPEG requires this */
484 width = round_up(width, 8);
485 height = round_up(height, 8);
487 rv->proxy_size = proxy_size;
490 get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE);
491 BLI_make_existing_file(fname);
493 rv->of = avformat_alloc_context();
494 rv->of->oformat = av_guess_format("avi", NULL, NULL);
496 BLI_strncpy(rv->of->filename, fname, sizeof(rv->of->filename));
498 fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename);
500 rv->st = avformat_new_stream(rv->of, NULL);
503 rv->c = rv->st->codec;
504 rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
505 rv->c->codec_id = AV_CODEC_ID_MJPEG;
506 rv->c->width = width;
507 rv->c->height = height;
509 rv->of->oformat->video_codec = rv->c->codec_id;
510 rv->codec = avcodec_find_encoder(rv->c->codec_id);
513 fprintf(stderr, "No ffmpeg MJPEG encoder available? "
514 "Proxy not built!\n");
519 if (rv->codec->pix_fmts) {
520 rv->c->pix_fmt = rv->codec->pix_fmts[0];
523 rv->c->pix_fmt = PIX_FMT_YUVJ420P;
526 rv->c->sample_aspect_ratio =
527 rv->st->sample_aspect_ratio =
528 st->codec->sample_aspect_ratio;
530 rv->c->time_base.den = 25;
531 rv->c->time_base.num = 1;
532 rv->st->time_base = rv->c->time_base;
534 /* there's no way to set JPEG quality in the same way as in AVI JPEG and image sequence,
535 * but this seems to be giving expected quality result */
536 ffmpeg_quality = (int)(1.0f + 30.0f * (1.0f - (float)quality / 100.0f) + 0.5f);
537 av_opt_set_int(rv->c, "qmin", ffmpeg_quality, 0);
538 av_opt_set_int(rv->c, "qmax", ffmpeg_quality, 0);
540 if (rv->of->flags & AVFMT_GLOBALHEADER) {
541 rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER;
544 if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) {
545 fprintf(stderr, "Couldn't open outputfile! "
546 "Proxy not built!\n");
551 avcodec_open2(rv->c, rv->codec, NULL);
553 rv->orig_height = av_get_cropped_height_from_codec(st->codec);
555 if (st->codec->width != width || st->codec->height != height ||
556 st->codec->pix_fmt != rv->c->pix_fmt)
558 rv->frame = avcodec_alloc_frame();
559 avpicture_fill((AVPicture *) rv->frame,
560 MEM_mallocN(avpicture_get_size(
562 round_up(width, 16), height),
563 "alloc proxy output frame"),
564 rv->c->pix_fmt, round_up(width, 16), height);
566 rv->sws_ctx = sws_getContext(
572 SWS_FAST_BILINEAR | SWS_PRINT_INFO,
576 if (avformat_write_header(rv->of, NULL) < 0) {
577 fprintf(stderr, "Couldn't set output parameters? "
578 "Proxy not built!\n");
586 static int add_to_proxy_output_ffmpeg(
587 struct proxy_output_ctx *ctx, AVFrame *frame)
589 AVPacket packet = { 0 };
592 av_init_packet(&packet);
598 if (ctx->sws_ctx && frame &&
599 (frame->data[0] || frame->data[1] ||
600 frame->data[2] || frame->data[3]))
602 sws_scale(ctx->sws_ctx, (const uint8_t *const *) frame->data,
603 frame->linesize, 0, ctx->orig_height,
604 ctx->frame->data, ctx->frame->linesize);
607 frame = ctx->sws_ctx ? (frame ? ctx->frame : 0) : frame;
610 frame->pts = ctx->cfra++;
613 ret = avcodec_encode_video2(ctx->c, &packet, frame, &got_output);
615 fprintf(stderr, "Error encoding proxy frame %d for '%s'\n",
616 ctx->cfra - 1, ctx->of->filename);
621 if (packet.pts != AV_NOPTS_VALUE) {
622 packet.pts = av_rescale_q(packet.pts,
626 if (packet.dts != AV_NOPTS_VALUE) {
627 packet.dts = av_rescale_q(packet.dts,
632 packet.stream_index = ctx->st->index;
634 if (av_interleaved_write_frame(ctx->of, &packet) != 0) {
635 fprintf(stderr, "Error writing proxy frame %d "
636 "into '%s'\n", ctx->cfra - 1,
648 static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx,
651 char fname[FILE_MAX];
652 char fname_tmp[FILE_MAX];
659 while (add_to_proxy_output_ffmpeg(ctx, NULL)) {}
662 avcodec_flush_buffers(ctx->c);
664 av_write_trailer(ctx->of);
666 avcodec_close(ctx->c);
668 if (ctx->of->oformat) {
669 if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
670 avio_close(ctx->of->pb);
673 avformat_free_context(ctx->of);
676 sws_freeContext(ctx->sws_ctx);
678 MEM_freeN(ctx->frame->data[0]);
682 get_proxy_filename(ctx->anim, ctx->proxy_size,
689 get_proxy_filename(ctx->anim, ctx->proxy_size,
692 BLI_rename(fname_tmp, fname);
698 typedef struct FFmpegIndexBuilderContext {
701 AVFormatContext *iFormatCtx;
702 AVCodecContext *iCodecCtx;
710 struct proxy_output_ctx *proxy_ctx[IMB_PROXY_MAX_SLOT];
711 anim_index_builder *indexer[IMB_TC_MAX_SLOT];
713 IMB_Timecode_Type tcs_in_use;
714 IMB_Proxy_Size proxy_sizes_in_use;
716 unsigned long long seek_pos;
717 unsigned long long last_seek_pos;
718 unsigned long long seek_pos_dts;
719 unsigned long long seek_pos_pts;
720 unsigned long long last_seek_pos_dts;
721 unsigned long long start_pts;
723 double pts_time_base;
724 int frameno, frameno_gapless;
726 } FFmpegIndexBuilderContext;
728 static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
729 IMB_Proxy_Size proxy_sizes_in_use, int quality)
731 FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext), "FFmpeg index builder context");
732 int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
733 int num_indexers = IMB_TC_MAX_SLOT;
736 context->tcs_in_use = tcs_in_use;
737 context->proxy_sizes_in_use = proxy_sizes_in_use;
738 context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
739 context->num_indexers = IMB_TC_MAX_SLOT;
741 memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
742 memset(context->indexer, 0, sizeof(context->indexer));
744 if (avformat_open_input(&context->iFormatCtx, anim->name, NULL, NULL) != 0) {
749 if (avformat_find_stream_info(context->iFormatCtx, NULL) < 0) {
750 avformat_close_input(&context->iFormatCtx);
755 streamcount = anim->streamindex;
757 /* Find the video stream */
758 context->videoStream = -1;
759 for (i = 0; i < context->iFormatCtx->nb_streams; i++)
760 if (context->iFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
761 if (streamcount > 0) {
765 context->videoStream = i;
769 if (context->videoStream == -1) {
770 avformat_close_input(&context->iFormatCtx);
775 context->iStream = context->iFormatCtx->streams[context->videoStream];
776 context->iCodecCtx = context->iStream->codec;
778 context->iCodec = avcodec_find_decoder(context->iCodecCtx->codec_id);
780 if (context->iCodec == NULL) {
781 avformat_close_input(&context->iFormatCtx);
786 context->iCodecCtx->workaround_bugs = 1;
788 if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) {
789 avformat_close_input(&context->iFormatCtx);
794 for (i = 0; i < num_proxy_sizes; i++) {
795 if (proxy_sizes_in_use & proxy_sizes[i]) {
796 context->proxy_ctx[i] = alloc_proxy_output_ffmpeg(
797 anim, context->iStream, proxy_sizes[i],
798 context->iCodecCtx->width * proxy_fac[i],
799 av_get_cropped_height_from_codec(
800 context->iCodecCtx) * proxy_fac[i],
802 if (!context->proxy_ctx[i]) {
803 proxy_sizes_in_use &= ~proxy_sizes[i];
808 for (i = 0; i < num_indexers; i++) {
809 if (tcs_in_use & tc_types[i]) {
810 char fname[FILE_MAX];
812 get_tc_filename(anim, tc_types[i], fname);
814 context->indexer[i] = IMB_index_builder_create(fname);
815 if (!context->indexer[i]) {
816 tcs_in_use &= ~tc_types[i];
821 return (IndexBuildContext *)context;
824 static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int stop)
828 for (i = 0; i < context->num_indexers; i++) {
829 if (context->tcs_in_use & tc_types[i]) {
830 IMB_index_builder_finish(context->indexer[i], stop);
834 for (i = 0; i < context->num_proxy_sizes; i++) {
835 if (context->proxy_sizes_in_use & proxy_sizes[i]) {
836 free_proxy_output_ffmpeg(context->proxy_ctx[i], stop);
840 avcodec_close(context->iCodecCtx);
841 avformat_close_input(&context->iFormatCtx);
846 static void index_rebuild_ffmpeg_proc_decoded_frame(
847 FFmpegIndexBuilderContext *context,
848 AVPacket * curr_packet,
852 unsigned long long s_pos = context->seek_pos;
853 unsigned long long s_dts = context->seek_pos_dts;
854 unsigned long long pts = av_get_pts_from_frame(context->iFormatCtx, in_frame);
856 for (i = 0; i < context->num_proxy_sizes; i++) {
857 add_to_proxy_output_ffmpeg(context->proxy_ctx[i], in_frame);
860 if (!context->start_pts_set) {
861 context->start_pts = pts;
862 context->start_pts_set = TRUE;
865 context->frameno = floor((pts - context->start_pts) *
866 context->pts_time_base *
867 context->frame_rate + 0.5);
869 /* decoding starts *always* on I-Frames,
870 * so: P-Frames won't work, even if all the
871 * information is in place, when we seek
872 * to the I-Frame presented *after* the P-Frame,
873 * but located before the P-Frame within
876 if (pts < context->seek_pos_pts) {
877 s_pos = context->last_seek_pos;
878 s_dts = context->last_seek_pos_dts;
881 for (i = 0; i < context->num_indexers; i++) {
882 if (context->tcs_in_use & tc_types[i]) {
883 int tc_frameno = context->frameno;
885 if (tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS)
886 tc_frameno = context->frameno_gapless;
888 IMB_index_builder_proc_frame(
897 context->frameno_gapless++;
900 static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
901 short *stop, short *do_update, float *progress)
903 AVFrame *in_frame = 0;
904 AVPacket next_packet;
905 uint64_t stream_size;
907 memset(&next_packet, 0, sizeof(AVPacket));
909 in_frame = avcodec_alloc_frame();
911 stream_size = avio_size(context->iFormatCtx->pb);
913 context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iStream));
914 context->pts_time_base = av_q2d(context->iStream->time_base);
916 while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
917 int frame_finished = 0;
918 float next_progress = (float)((int)floor(((double) next_packet.pos) * 100 /
919 ((double) stream_size) + 0.5)) / 100;
921 if (*progress != next_progress) {
922 *progress = next_progress;
927 av_free_packet(&next_packet);
931 if (next_packet.stream_index == context->videoStream) {
932 if (next_packet.flags & AV_PKT_FLAG_KEY) {
933 context->last_seek_pos = context->seek_pos;
934 context->last_seek_pos_dts = context->seek_pos_dts;
935 context->seek_pos = next_packet.pos;
936 context->seek_pos_dts = next_packet.dts;
937 context->seek_pos_pts = next_packet.pts;
940 avcodec_decode_video2(
941 context->iCodecCtx, in_frame, &frame_finished,
945 if (frame_finished) {
946 index_rebuild_ffmpeg_proc_decoded_frame(
947 context, &next_packet, in_frame);
949 av_free_packet(&next_packet);
952 /* process pictures still stuck in decoder engine after EOF
953 * according to ffmpeg docs using 0-size packets.
955 * At least, if we haven't already stopped... */
957 /* this creates the 0-size packet and prevents a memory leak. */
958 av_free_packet(&next_packet);
966 avcodec_decode_video2(
967 context->iCodecCtx, in_frame, &frame_finished,
970 if (frame_finished) {
971 index_rebuild_ffmpeg_proc_decoded_frame(
972 context, &next_packet, in_frame);
974 } while (frame_finished);
984 /* ----------------------------------------------------------------------
985 * - internal AVI (fallback) rebuilder
986 * ---------------------------------------------------------------------- */
989 typedef struct FallbackIndexBuilderContext {
993 AviMovie *proxy_ctx[IMB_PROXY_MAX_SLOT];
994 IMB_Proxy_Size proxy_sizes_in_use;
995 } FallbackIndexBuilderContext;
997 static AviMovie *alloc_proxy_output_avi(
998 struct anim *anim, char *filename, int width, int height,
1005 short frs_sec = 25; /* it doesn't really matter for proxies,
1006 * but sane defaults help anyways...*/
1007 float frs_sec_base = 1.0;
1009 IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base);
1014 framerate = (double) frs_sec / (double) frs_sec_base;
1016 avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
1018 format = AVI_FORMAT_MJPEG;
1020 if (AVI_open_compress(filename, avi, 1, format) != AVI_ERROR_NONE) {
1025 AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
1026 AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
1027 AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
1028 AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
1031 avi->odd_fields = 0;
1036 static IndexBuildContext *index_fallback_create_context(struct anim *anim, IMB_Timecode_Type UNUSED(tcs_in_use),
1037 IMB_Proxy_Size proxy_sizes_in_use, int quality)
1039 FallbackIndexBuilderContext *context;
1042 /* since timecode indices only work with ffmpeg right now,
1043 * don't know a sensible fallback here...
1045 * so no proxies, no game to play...
1047 if (proxy_sizes_in_use == IMB_PROXY_NONE) {
1051 context = MEM_callocN(sizeof(FallbackIndexBuilderContext), "fallback index builder context");
1053 context->anim = anim;
1054 context->proxy_sizes_in_use = proxy_sizes_in_use;
1056 memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
1058 for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1059 if (context->proxy_sizes_in_use & proxy_sizes[i]) {
1060 char fname[FILE_MAX];
1062 get_proxy_filename(anim, proxy_sizes[i], fname, TRUE);
1063 BLI_make_existing_file(fname);
1065 context->proxy_ctx[i] = alloc_proxy_output_avi(anim, fname,
1066 anim->x * proxy_fac[i], anim->y * proxy_fac[i], quality);
1070 return (IndexBuildContext *)context;
1073 static void index_rebuild_fallback_finish(FallbackIndexBuilderContext *context, int stop)
1075 struct anim *anim = context->anim;
1076 char fname[FILE_MAX];
1077 char fname_tmp[FILE_MAX];
1080 for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1081 if (context->proxy_sizes_in_use & proxy_sizes[i]) {
1082 AVI_close_compress(context->proxy_ctx[i]);
1083 MEM_freeN(context->proxy_ctx[i]);
1085 get_proxy_filename(anim, proxy_sizes[i], fname_tmp, TRUE);
1086 get_proxy_filename(anim, proxy_sizes[i], fname, FALSE);
1093 rename(fname_tmp, fname);
1099 static void index_rebuild_fallback(FallbackIndexBuilderContext *context,
1100 short *stop, short *do_update, float *progress)
1102 int cnt = IMB_anim_get_duration(context->anim, IMB_TC_NONE);
1104 struct anim *anim = context->anim;
1106 for (pos = 0; pos < cnt; pos++) {
1107 struct ImBuf *ibuf = IMB_anim_absolute(anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
1108 struct ImBuf *tmp_ibuf = IMB_dupImBuf(ibuf);
1109 float next_progress = (float) pos / (float) cnt;
1111 if (*progress != next_progress) {
1112 *progress = next_progress;
1120 IMB_flipy(tmp_ibuf);
1122 for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1123 if (context->proxy_sizes_in_use & proxy_sizes[i]) {
1124 int x = anim->x * proxy_fac[i];
1125 int y = anim->y * proxy_fac[i];
1127 struct ImBuf *s_ibuf = IMB_dupImBuf(tmp_ibuf);
1129 IMB_scalefastImBuf(s_ibuf, x, y);
1131 IMB_convert_rgba_to_abgr(s_ibuf);
1133 AVI_write_frame(context->proxy_ctx[i], pos,
1135 s_ibuf->rect, x * y * 4);
1137 /* note that libavi free's the buffer... */
1138 s_ibuf->rect = NULL;
1140 IMB_freeImBuf(s_ibuf);
1144 IMB_freeImBuf(tmp_ibuf);
1145 IMB_freeImBuf(ibuf);
1149 #endif /* WITH_AVI */
1151 /* ----------------------------------------------------------------------
1153 * ---------------------------------------------------------------------- */
1155 IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
1156 IMB_Proxy_Size proxy_sizes_in_use, int quality)
1158 IndexBuildContext *context = NULL;
1160 switch (anim->curtype) {
1163 context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_in_use, quality);
1168 context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_in_use, quality);
1174 context->anim_type = anim->curtype;
1178 (void)tcs_in_use, (void)proxy_sizes_in_use, (void)quality;
1181 void IMB_anim_index_rebuild(struct IndexBuildContext *context,
1182 short *stop, short *do_update, float *progress)
1184 switch (context->anim_type) {
1187 index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
1192 index_rebuild_fallback((FallbackIndexBuilderContext *)context, stop, do_update, progress);
1197 (void)stop, (void)do_update, (void)progress;
1200 void IMB_anim_index_rebuild_finish(IndexBuildContext *context, short stop)
1202 switch (context->anim_type) {
1205 index_rebuild_ffmpeg_finish((FFmpegIndexBuilderContext *)context, stop);
1210 index_rebuild_fallback_finish((FallbackIndexBuilderContext *)context, stop);
1216 (void)proxy_sizes; /* static defined at top of the file */
1220 void IMB_free_indices(struct anim *anim)
1224 for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
1225 if (anim->proxy_anim[i]) {
1226 IMB_close_anim(anim->proxy_anim[i]);
1227 anim->proxy_anim[i] = NULL;
1231 for (i = 0; i < IMB_TC_MAX_SLOT; i++) {
1232 if (anim->curr_idx[i]) {
1233 IMB_indexer_close(anim->curr_idx[i]);
1234 anim->curr_idx[i] = NULL;
1239 anim->proxies_tried = 0;
1240 anim->indices_tried = 0;
1243 void IMB_anim_set_index_dir(struct anim *anim, const char *dir)
1245 if (strcmp(anim->index_dir, dir) == 0) {
1248 BLI_strncpy(anim->index_dir, dir, sizeof(anim->index_dir));
1250 IMB_free_indices(anim);
1253 struct anim *IMB_anim_open_proxy(
1254 struct anim *anim, IMB_Proxy_Size preview_size)
1256 char fname[FILE_MAX];
1257 int i = IMB_proxy_size_to_array_index(preview_size);
1259 if (anim->proxy_anim[i]) {
1260 return anim->proxy_anim[i];
1263 if (anim->proxies_tried & preview_size) {
1267 get_proxy_filename(anim, preview_size, fname, FALSE);
1269 /* proxies are generated in default color space */
1270 anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0, NULL);
1272 anim->proxies_tried |= preview_size;
1274 return anim->proxy_anim[i];
1277 struct anim_index *IMB_anim_open_index(
1278 struct anim *anim, IMB_Timecode_Type tc)
1280 char fname[FILE_MAX];
1281 int i = IMB_timecode_to_array_index(tc);
1283 if (anim->curr_idx[i]) {
1284 return anim->curr_idx[i];
1287 if (anim->indices_tried & tc) {
1291 get_tc_filename(anim, tc, fname);
1293 anim->curr_idx[i] = IMB_indexer_open(fname);
1295 anim->indices_tried |= tc;
1297 return anim->curr_idx[i];
1300 int IMB_anim_index_get_frame_index(struct anim *anim, IMB_Timecode_Type tc,
1303 struct anim_index *idx = IMB_anim_open_index(anim, tc);
1309 return IMB_indexer_get_frame_index(idx, position);