89ae32ee2b3c56ff5f243bb8ec673865fd34966f
[blender.git] / source / blender / imbuf / intern / anim_movie.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
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.
8  *
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.
13  *
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.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/imbuf/intern/anim_movie.c
29  *  \ingroup imbuf
30  */
31
32
33 #ifdef _WIN32
34 #define INC_OLE2
35 #include <windows.h>
36 #include <windowsx.h>
37 #include <mmsystem.h>
38 #include <memory.h>
39 #include <commdlg.h>
40 #include <vfw.h>
41
42 #undef AVIIF_KEYFRAME /* redefined in AVI_avi.h */
43 #undef AVIIF_LIST /* redefined in AVI_avi.h */
44
45 #define FIXCC(fcc) \
46         { \
47                 if (fcc == 0)       { fcc = mmioFOURCC('N', 'o', 'n', 'e'); } \
48                 if (fcc == BI_RLE8) { fcc = mmioFOURCC('R', 'l', 'e', '8'); } \
49         } (void)0
50
51 #endif
52
53 #include <sys/types.h>
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <math.h>
58 #include <limits.h>
59 #ifndef _WIN32
60 #include <dirent.h>
61 #else
62 #include <io.h>
63 #endif
64
65 #include "BLI_utildefines.h"
66 #include "BLI_string.h"
67 #include "BLI_path_util.h"
68
69 #include "MEM_guardedalloc.h"
70
71 #ifdef WITH_AVI
72 #  include "AVI_avi.h"
73 #endif
74
75 #include "IMB_imbuf_types.h"
76 #include "IMB_imbuf.h"
77
78 #include "IMB_colormanagement.h"
79 #include "IMB_colormanagement_intern.h"
80
81 #include "IMB_anim.h"
82 #include "IMB_indexer.h"
83 #include "IMB_metadata.h"
84
85 #ifdef WITH_FFMPEG
86 #  include "BKE_global.h"  /* ENDIAN_ORDER */
87
88 #  include <libavformat/avformat.h>
89 #  include <libavcodec/avcodec.h>
90 #  include <libavutil/rational.h>
91 #  include <libswscale/swscale.h>
92
93 #  include "ffmpeg_compat.h"
94 #endif //WITH_FFMPEG
95
96 int ismovie(const char *UNUSED(filepath))
97 {
98         return 0;
99 }
100
101 /* never called, just keep the linker happy */
102 static int startmovie(struct anim *UNUSED(anim))
103 {
104         return 1;
105 }
106 static ImBuf *movie_fetchibuf(struct anim *UNUSED(anim), int UNUSED(position))
107 {
108         return NULL;
109 }
110 static void free_anim_movie(struct anim *UNUSED(anim))
111 {
112         /* pass */
113 }
114
115
116 #if defined(_WIN32)
117 # define PATHSEPARATOR '\\'
118 #else
119 # define PATHSEPARATOR '/'
120 #endif
121
122 static int an_stringdec(const char *string, char *head, char *tail, unsigned short *numlen)
123 {
124         unsigned short len, nume, nums = 0;
125         short i;
126         bool found = false;
127
128         len = strlen(string);
129         nume = len;
130
131         for (i = len - 1; i >= 0; i--) {
132                 if (string[i] == PATHSEPARATOR) break;
133                 if (isdigit(string[i])) {
134                         if (found) {
135                                 nums = i;
136                         }
137                         else {
138                                 nume = i;
139                                 nums = i;
140                                 found = true;
141                         }
142                 }
143                 else {
144                         if (found) break;
145                 }
146         }
147         if (found) {
148                 strcpy(tail, &string[nume + 1]);
149                 strcpy(head, string);
150                 head[nums] = '\0';
151                 *numlen = nume - nums + 1;
152                 return ((int)atoi(&(string[nums])));
153         }
154         tail[0] = '\0';
155         strcpy(head, string);
156         *numlen = 0;
157         return true;
158 }
159
160
161 static void an_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic)
162 {
163         BLI_stringenc(string, head, tail, numlen, pic);
164 }
165
166 #ifdef WITH_AVI
167 static void free_anim_avi(struct anim *anim)
168 {
169 #if defined(_WIN32)
170         int i;
171 #endif
172
173         if (anim == NULL) return;
174         if (anim->avi == NULL) return;
175
176         AVI_close(anim->avi);
177         MEM_freeN(anim->avi);
178         anim->avi = NULL;
179
180 #if defined(_WIN32)
181
182         if (anim->pgf) {
183                 AVIStreamGetFrameClose(anim->pgf);
184                 anim->pgf = NULL;
185         }
186
187         for (i = 0; i < anim->avistreams; i++) {
188                 AVIStreamRelease(anim->pavi[i]);
189         }
190         anim->avistreams = 0;
191
192         if (anim->pfileopen) {
193                 AVIFileRelease(anim->pfile);
194                 anim->pfileopen = 0;
195                 AVIFileExit();
196         }
197 #endif
198
199         anim->duration = 0;
200 }
201 #endif  /* WITH_AVI */
202
203 #ifdef WITH_FFMPEG
204 static void free_anim_ffmpeg(struct anim *anim);
205 #endif
206
207 void IMB_free_anim(struct anim *anim)
208 {
209         if (anim == NULL) {
210                 printf("free anim, anim == NULL\n");
211                 return;
212         }
213
214         free_anim_movie(anim);
215
216 #ifdef WITH_AVI
217         free_anim_avi(anim);
218 #endif
219
220 #ifdef WITH_FFMPEG
221         free_anim_ffmpeg(anim);
222 #endif
223         IMB_free_indices(anim);
224         IMB_metadata_free(anim->metadata);
225
226         MEM_freeN(anim);
227 }
228
229 void IMB_close_anim(struct anim *anim)
230 {
231         if (anim == NULL) return;
232
233         IMB_free_anim(anim);
234 }
235
236 void IMB_close_anim_proxies(struct anim *anim)
237 {
238         if (anim == NULL)
239                 return;
240
241         IMB_free_indices(anim);
242 }
243
244 struct IDProperty *IMB_anim_load_metadata(struct anim *anim)
245 {
246         switch (anim->curtype) {
247                 case ANIM_FFMPEG:
248                 {
249 #ifdef WITH_FFMPEG
250                         AVDictionaryEntry *entry = NULL;
251
252                         BLI_assert(anim->pFormatCtx != NULL);
253                         av_log(anim->pFormatCtx, AV_LOG_DEBUG, "METADATA FETCH\n");
254
255                         while (true) {
256                                 entry = av_dict_get(anim->pFormatCtx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX);
257                                 if (entry == NULL) break;
258
259                                 /* Delay creation of the property group until there is actual metadata to put in there. */
260                                 IMB_metadata_ensure(&anim->metadata);
261                                 IMB_metadata_set_field(anim->metadata, entry->key, entry->value);
262                         }
263 #endif
264                         break;
265                 }
266                 case ANIM_SEQUENCE:
267                 case ANIM_AVI:
268                 case ANIM_MOVIE:
269                         /* TODO */
270                         break;
271                 case ANIM_NONE:
272                 default:
273                         break;
274         }
275         return anim->metadata;
276 }
277
278 struct anim *IMB_open_anim(const char *name, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
279 {
280         struct anim *anim;
281
282         BLI_assert(!BLI_path_is_rel(name));
283
284         anim = (struct anim *)MEM_callocN(sizeof(struct anim), "anim struct");
285         if (anim != NULL) {
286                 if (colorspace) {
287                         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
288                         BLI_strncpy(anim->colorspace, colorspace, sizeof(anim->colorspace));
289                 }
290                 else {
291                         colorspace_set_default_role(anim->colorspace, sizeof(anim->colorspace), COLOR_ROLE_DEFAULT_BYTE);
292                 }
293
294                 BLI_strncpy(anim->name, name, sizeof(anim->name));
295                 anim->ib_flags = ib_flags;
296                 anim->streamindex = streamindex;
297         }
298         return(anim);
299 }
300
301 void IMB_suffix_anim(struct anim *anim, const char *suffix)
302 {
303         BLI_strncpy(anim->suffix, suffix, sizeof(anim->suffix));
304 }
305
306 #ifdef WITH_AVI
307 static int startavi(struct anim *anim)
308 {
309
310         AviError avierror;
311 #if defined(_WIN32)
312         HRESULT hr;
313         int i, firstvideo = -1;
314         int streamcount;
315         BYTE abFormat[1024];
316         LONG l;
317         LPBITMAPINFOHEADER lpbi;
318         AVISTREAMINFO avis;
319
320         streamcount = anim->streamindex;
321 #endif
322
323         anim->avi = MEM_callocN(sizeof(AviMovie), "animavi");
324
325         if (anim->avi == NULL) {
326                 printf("Can't open avi: %s\n", anim->name);
327                 return -1;
328         }
329
330         avierror = AVI_open_movie(anim->name, anim->avi);
331
332 #if defined(_WIN32)
333         if (avierror == AVI_ERROR_COMPRESSION) {
334                 AVIFileInit();
335                 hr = AVIFileOpen(&anim->pfile, anim->name, OF_READ, 0L);
336                 if (hr == 0) {
337                         anim->pfileopen = 1;
338                         for (i = 0; i < MAXNUMSTREAMS; i++) {
339                                 if (AVIFileGetStream(anim->pfile, &anim->pavi[i], 0L, i) != AVIERR_OK) {
340                                         break;
341                                 }
342
343                                 AVIStreamInfo(anim->pavi[i], &avis, sizeof(avis));
344                                 if ((avis.fccType == streamtypeVIDEO) && (firstvideo == -1)) {
345                                         if (streamcount > 0) {
346                                                 streamcount--;
347                                                 continue;
348                                         }
349                                         anim->pgf = AVIStreamGetFrameOpen(anim->pavi[i], NULL);
350                                         if (anim->pgf) {
351                                                 firstvideo = i;
352
353                                                 /* get stream length */
354                                                 anim->avi->header->TotalFrames = AVIStreamLength(anim->pavi[i]);
355
356                                                 /* get information about images inside the stream */
357                                                 l = sizeof(abFormat);
358                                                 AVIStreamReadFormat(anim->pavi[i], 0, &abFormat, &l);
359                                                 lpbi = (LPBITMAPINFOHEADER)abFormat;
360                                                 anim->avi->header->Height = lpbi->biHeight;
361                                                 anim->avi->header->Width = lpbi->biWidth;
362                                         }
363                                         else {
364                                                 FIXCC(avis.fccHandler);
365                                                 FIXCC(avis.fccType);
366                                                 printf("Can't find AVI decoder for type : %4.4hs/%4.4hs\n",
367                                                        (LPSTR)&avis.fccType,
368                                                        (LPSTR)&avis.fccHandler);
369                                         }
370                                 }
371                         }
372
373                         /* register number of opened avistreams */
374                         anim->avistreams = i;
375
376                         /*
377                          * Couldn't get any video streams out of this file
378                          */
379                         if ((anim->avistreams == 0) || (firstvideo == -1)) {
380                                 avierror = AVI_ERROR_FORMAT;
381                         }
382                         else {
383                                 avierror = AVI_ERROR_NONE;
384                                 anim->firstvideo = firstvideo;
385                         }
386                 }
387                 else {
388                         AVIFileExit();
389                 }
390         }
391 #endif
392
393         if (avierror != AVI_ERROR_NONE) {
394                 AVI_print_error(avierror);
395                 printf("Error loading avi: %s\n", anim->name);
396                 free_anim_avi(anim);
397                 return -1;
398         }
399
400         anim->duration = anim->avi->header->TotalFrames;
401         anim->params = NULL;
402
403         anim->x = anim->avi->header->Width;
404         anim->y = anim->avi->header->Height;
405         anim->interlacing = 0;
406         anim->orientation = 0;
407         anim->framesize = anim->x * anim->y * 4;
408
409         anim->curposition = 0;
410         anim->preseek = 0;
411
412         /*  printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/
413
414         return 0;
415 }
416 #endif  /* WITH_AVI */
417
418 #ifdef WITH_AVI
419 static ImBuf *avi_fetchibuf(struct anim *anim, int position)
420 {
421         ImBuf *ibuf = NULL;
422         int *tmp;
423         int y;
424
425         if (anim == NULL) {
426                 return NULL;
427         }
428
429 #if defined(_WIN32)
430         if (anim->avistreams) {
431                 LPBITMAPINFOHEADER lpbi;
432
433                 if (anim->pgf) {
434                         lpbi = AVIStreamGetFrame(anim->pgf, position + AVIStreamStart(anim->pavi[anim->firstvideo]));
435                         if (lpbi) {
436                                 ibuf = IMB_ibImageFromMemory((unsigned char *) lpbi, 100, IB_rect, anim->colorspace, "<avi_fetchibuf>");
437 //Oh brother...
438                         }
439                 }
440         }
441         else
442 #endif
443         {
444                 ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect);
445
446                 tmp = AVI_read_frame(anim->avi, AVI_FORMAT_RGB32, position,
447                                      AVI_get_stream(anim->avi, AVIST_VIDEO, 0));
448
449                 if (tmp == NULL) {
450                         printf("Error reading frame from AVI: '%s'\n", anim->name);
451                         IMB_freeImBuf(ibuf);
452                         return NULL;
453                 }
454
455                 for (y = 0; y < anim->y; y++) {
456                         memcpy(&(ibuf->rect)[((anim->y - y) - 1) * anim->x],  &tmp[y * anim->x],
457                                anim->x * 4);
458                 }
459
460                 MEM_freeN(tmp);
461         }
462
463         ibuf->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);
464
465         return ibuf;
466 }
467 #endif  /* WITH_AVI */
468
469 #ifdef WITH_FFMPEG
470
471 BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim)
472 {
473         return (anim->x & 31) != 0;
474 }
475
476 static int startffmpeg(struct anim *anim)
477 {
478         int i, videoStream;
479
480         AVCodec *pCodec;
481         AVFormatContext *pFormatCtx = NULL;
482         AVCodecContext *pCodecCtx;
483         AVRational frame_rate;
484         int frs_num;
485         double frs_den;
486         int streamcount;
487
488 #ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
489         /* The following for color space determination */
490         int srcRange, dstRange, brightness, contrast, saturation;
491         int *table;
492         const int *inv_table;
493 #endif
494
495         if (anim == NULL) return(-1);
496
497         streamcount = anim->streamindex;
498
499         if (avformat_open_input(&pFormatCtx, anim->name, NULL, NULL) != 0) {
500                 return -1;
501         }
502
503         if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
504                 avformat_close_input(&pFormatCtx);
505                 return -1;
506         }
507
508         av_dump_format(pFormatCtx, 0, anim->name, 0);
509
510
511         /* Find the video stream */
512         videoStream = -1;
513
514         for (i = 0; i < pFormatCtx->nb_streams; i++)
515                 if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
516                         if (streamcount > 0) {
517                                 streamcount--;
518                                 continue;
519                         }
520                         videoStream = i;
521                         break;
522                 }
523
524         if (videoStream == -1) {
525                 avformat_close_input(&pFormatCtx);
526                 return -1;
527         }
528
529         pCodecCtx = pFormatCtx->streams[videoStream]->codec;
530
531         /* Find the decoder for the video stream */
532         pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
533         if (pCodec == NULL) {
534                 avformat_close_input(&pFormatCtx);
535                 return -1;
536         }
537
538         pCodecCtx->workaround_bugs = 1;
539
540         if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
541                 avformat_close_input(&pFormatCtx);
542                 return -1;
543         }
544         if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) {
545                 avcodec_close(anim->pCodecCtx);
546                 avformat_close_input(&pFormatCtx);
547                 return -1;
548         }
549
550         frame_rate = av_get_r_frame_rate_compat(pFormatCtx, pFormatCtx->streams[videoStream]);
551         if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
552                 anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
553         }
554         else {
555                 anim->duration = (int)(pFormatCtx->duration *
556                                        av_q2d(frame_rate) /
557                                        AV_TIME_BASE + 0.5f);
558         }
559
560         frs_num = frame_rate.num;
561         frs_den = frame_rate.den;
562
563         frs_den *= AV_TIME_BASE;
564
565         while (frs_num % 10 == 0 && frs_den >= 2.0 && frs_num > 10) {
566                 frs_num /= 10;
567                 frs_den /= 10;
568         }
569
570         anim->frs_sec = frs_num;
571         anim->frs_sec_base = frs_den;
572
573         anim->params = 0;
574
575         anim->x = pCodecCtx->width;
576         anim->y = av_get_cropped_height_from_codec(pCodecCtx);
577
578         anim->pFormatCtx = pFormatCtx;
579         anim->pCodecCtx = pCodecCtx;
580         anim->pCodec = pCodec;
581         anim->videoStream = videoStream;
582
583         anim->interlacing = 0;
584         anim->orientation = 0;
585         anim->framesize = anim->x * anim->y * 4;
586
587         anim->curposition = -1;
588         anim->last_frame = 0;
589         anim->last_pts = -1;
590         anim->next_pts = -1;
591         anim->next_packet.stream_index = -1;
592
593         anim->pFrame = av_frame_alloc();
594         anim->pFrameComplete = false;
595         anim->pFrameDeinterlaced = av_frame_alloc();
596         anim->pFrameRGB = av_frame_alloc();
597
598         if (need_aligned_ffmpeg_buffer(anim)) {
599                 anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
600                 anim->pFrameRGB->width  = anim->x;
601                 anim->pFrameRGB->height = anim->y;
602
603                 if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) {
604                         fprintf(stderr, "Could not allocate frame data.\n");
605                         avcodec_close(anim->pCodecCtx);
606                         avformat_close_input(&anim->pFormatCtx);
607                         av_frame_free(&anim->pFrameRGB);
608                         av_frame_free(&anim->pFrameDeinterlaced);
609                         av_frame_free(&anim->pFrame);
610                         anim->pCodecCtx = NULL;
611                         return -1;
612                 }
613         }
614
615         if (avpicture_get_size(AV_PIX_FMT_RGBA, anim->x, anim->y) !=
616             anim->x * anim->y * 4)
617         {
618                 fprintf(stderr,
619                         "ffmpeg has changed alloc scheme ... ARGHHH!\n");
620                 avcodec_close(anim->pCodecCtx);
621                 avformat_close_input(&anim->pFormatCtx);
622                 av_frame_free(&anim->pFrameRGB);
623                 av_frame_free(&anim->pFrameDeinterlaced);
624                 av_frame_free(&anim->pFrame);
625                 anim->pCodecCtx = NULL;
626                 return -1;
627         }
628
629         if (anim->ib_flags & IB_animdeinterlace) {
630                 avpicture_fill((AVPicture *) anim->pFrameDeinterlaced,
631                                MEM_callocN(avpicture_get_size(
632                                                anim->pCodecCtx->pix_fmt,
633                                                anim->pCodecCtx->width,
634                                                anim->pCodecCtx->height),
635                                            "ffmpeg deinterlace"),
636                                anim->pCodecCtx->pix_fmt,
637                                anim->pCodecCtx->width,
638                                anim->pCodecCtx->height);
639         }
640
641         if (pCodecCtx->has_b_frames) {
642                 anim->preseek = 25; /* FIXME: detect gopsize ... */
643         }
644         else {
645                 anim->preseek = 0;
646         }
647
648         anim->img_convert_ctx = sws_getContext(
649                 anim->x,
650                 anim->y,
651                 anim->pCodecCtx->pix_fmt,
652                 anim->x,
653                 anim->y,
654                 AV_PIX_FMT_RGBA,
655                 SWS_FAST_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
656                 NULL, NULL, NULL);
657
658         if (!anim->img_convert_ctx) {
659                 fprintf(stderr,
660                         "Can't transform color space??? Bailing out...\n");
661                 avcodec_close(anim->pCodecCtx);
662                 avformat_close_input(&anim->pFormatCtx);
663                 av_frame_free(&anim->pFrameRGB);
664                 av_frame_free(&anim->pFrameDeinterlaced);
665                 av_frame_free(&anim->pFrame);
666                 anim->pCodecCtx = NULL;
667                 return -1;
668         }
669
670 #ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
671         /* Try do detect if input has 0-255 YCbCR range (JFIF Jpeg MotionJpeg) */
672         if (!sws_getColorspaceDetails(anim->img_convert_ctx, (int **)&inv_table, &srcRange,
673                                       &table, &dstRange, &brightness, &contrast, &saturation))
674         {
675                 srcRange = srcRange || anim->pCodecCtx->color_range == AVCOL_RANGE_JPEG;
676                 inv_table = sws_getCoefficients(anim->pCodecCtx->colorspace);
677
678                 if (sws_setColorspaceDetails(anim->img_convert_ctx, (int *)inv_table, srcRange,
679                                              table, dstRange, brightness, contrast, saturation))
680                 {
681                         fprintf(stderr, "Warning: Could not set libswscale colorspace details.\n");
682                 }
683         }
684         else {
685                 fprintf(stderr, "Warning: Could not set libswscale colorspace details.\n");
686         }
687 #endif
688
689         return (0);
690 }
691
692 /* postprocess the image in anim->pFrame and do color conversion
693  * and deinterlacing stuff.
694  *
695  * Output is anim->last_frame
696  */
697
698 static void ffmpeg_postprocess(struct anim *anim)
699 {
700         AVFrame *input = anim->pFrame;
701         ImBuf *ibuf = anim->last_frame;
702         int filter_y = 0;
703
704         if (!anim->pFrameComplete) {
705                 return;
706         }
707
708         /* This means the data wasnt read properly,
709          * this check stops crashing */
710         if (input->data[0] == 0 && input->data[1] == 0 &&
711             input->data[2] == 0 && input->data[3] == 0)
712         {
713                 fprintf(stderr, "ffmpeg_fetchibuf: "
714                         "data not read properly...\n");
715                 return;
716         }
717
718         av_log(anim->pFormatCtx, AV_LOG_DEBUG,
719                "  POSTPROC: anim->pFrame planes: %p %p %p %p\n",
720                input->data[0], input->data[1], input->data[2],
721                input->data[3]);
722
723
724         if (anim->ib_flags & IB_animdeinterlace) {
725                 if (avpicture_deinterlace(
726                         (AVPicture *)
727                         anim->pFrameDeinterlaced,
728                         (const AVPicture *)
729                         anim->pFrame,
730                         anim->pCodecCtx->pix_fmt,
731                         anim->pCodecCtx->width,
732                         anim->pCodecCtx->height) < 0)
733                 {
734                         filter_y = true;
735                 }
736                 else {
737                         input = anim->pFrameDeinterlaced;
738                 }
739         }
740
741         if (!need_aligned_ffmpeg_buffer(anim)) {
742                 avpicture_fill((AVPicture *) anim->pFrameRGB,
743                                (unsigned char *) ibuf->rect,
744                                AV_PIX_FMT_RGBA, anim->x, anim->y);
745         }
746
747         if (ENDIAN_ORDER == B_ENDIAN) {
748                 int *dstStride   = anim->pFrameRGB->linesize;
749                 uint8_t **dst     = anim->pFrameRGB->data;
750                 int dstStride2[4] = { dstStride[0], 0, 0, 0 };
751                 uint8_t *dst2[4]  = { dst[0], 0, 0, 0 };
752                 int x, y, h, w;
753                 unsigned char *bottom;
754                 unsigned char *top;
755
756                 sws_scale(anim->img_convert_ctx,
757                           (const uint8_t *const *)input->data,
758                           input->linesize,
759                           0,
760                           anim->y,
761                           dst2,
762                           dstStride2);
763
764                 bottom = (unsigned char *) ibuf->rect;
765                 top = bottom + ibuf->x * (ibuf->y - 1) * 4;
766
767                 h = (ibuf->y + 1) / 2;
768                 w = ibuf->x;
769
770                 for (y = 0; y < h; y++) {
771                         unsigned char tmp[4];
772                         unsigned int *tmp_l =
773                             (unsigned int *) tmp;
774
775                         for (x = 0; x < w; x++) {
776                                 tmp[0] = bottom[0];
777                                 tmp[1] = bottom[1];
778                                 tmp[2] = bottom[2];
779                                 tmp[3] = bottom[3];
780
781                                 bottom[0] = top[0];
782                                 bottom[1] = top[1];
783                                 bottom[2] = top[2];
784                                 bottom[3] = top[3];
785
786                                 *(unsigned int *) top = *tmp_l;
787
788                                 bottom += 4;
789                                 top += 4;
790                         }
791                         top -= 8 * w;
792                 }
793         }
794         else {
795                 int *dstStride   = anim->pFrameRGB->linesize;
796                 uint8_t **dst     = anim->pFrameRGB->data;
797                 int dstStride2[4] = { -dstStride[0], 0, 0, 0 };
798                 uint8_t *dst2[4]  = { dst[0] + (anim->y - 1) * dstStride[0],
799                                           0, 0, 0 };
800
801                 sws_scale(anim->img_convert_ctx,
802                           (const uint8_t *const *)input->data,
803                           input->linesize,
804                           0,
805                           anim->y,
806                           dst2,
807                           dstStride2);
808         }
809
810         if (need_aligned_ffmpeg_buffer(anim)) {
811                 uint8_t *src = anim->pFrameRGB->data[0];
812                 uint8_t *dst = (uint8_t *) ibuf->rect;
813                 for (int y = 0; y < anim->y; y++) {
814                         memcpy(dst, src, anim->x * 4);
815                         dst += anim->x * 4;
816                         src += anim->pFrameRGB->linesize[0];
817                 }
818         }
819
820         if (filter_y) {
821                 IMB_filtery(ibuf);
822         }
823 }
824
825 /* decode one video frame also considering the packet read into next_packet */
826
827 static int ffmpeg_decode_video_frame(struct anim *anim)
828 {
829         int rval = 0;
830
831         av_log(anim->pFormatCtx, AV_LOG_DEBUG, "  DECODE VIDEO FRAME\n");
832
833         if (anim->next_packet.stream_index == anim->videoStream) {
834                 av_free_packet(&anim->next_packet);
835                 anim->next_packet.stream_index = -1;
836         }
837
838         while ((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) {
839                 av_log(anim->pFormatCtx,
840                        AV_LOG_DEBUG,
841                        "%sREAD: strID=%d (VID: %d) dts=%lld pts=%lld "
842                        "%s\n",
843                        (anim->next_packet.stream_index == anim->videoStream)
844                        ? "->" : "  ",
845                        anim->next_packet.stream_index,
846                        anim->videoStream,
847                        (anim->next_packet.dts == AV_NOPTS_VALUE) ? -1 :
848                        (long long int)anim->next_packet.dts,
849                        (anim->next_packet.pts == AV_NOPTS_VALUE) ? -1 :
850                        (long long int)anim->next_packet.pts,
851                        (anim->next_packet.flags & AV_PKT_FLAG_KEY) ?
852                        " KEY" : "");
853                 if (anim->next_packet.stream_index == anim->videoStream) {
854                         anim->pFrameComplete = 0;
855
856                         avcodec_decode_video2(
857                             anim->pCodecCtx,
858                             anim->pFrame, &anim->pFrameComplete,
859                             &anim->next_packet);
860
861                         if (anim->pFrameComplete) {
862                                 anim->next_pts = av_get_pts_from_frame(
863                                         anim->pFormatCtx, anim->pFrame);
864
865                                 av_log(anim->pFormatCtx,
866                                        AV_LOG_DEBUG,
867                                        "  FRAME DONE: next_pts=%lld "
868                                        "pkt_pts=%lld, guessed_pts=%lld\n",
869                                        (anim->pFrame->pts == AV_NOPTS_VALUE) ?
870                                        -1 : (long long int)anim->pFrame->pts,
871                                        (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ?
872                                        -1 : (long long int)anim->pFrame->pkt_pts,
873                                        (long long int)anim->next_pts);
874                                 break;
875                         }
876                 }
877                 av_free_packet(&anim->next_packet);
878                 anim->next_packet.stream_index = -1;
879         }
880
881         if (rval == AVERROR_EOF) {
882                 /* this sets size and data fields to zero,
883                  * which is necessary to decode the remaining data
884                  * in the decoder engine after EOF. It also prevents a memory
885                  * leak, since av_read_frame spills out a full size packet even
886                  * on EOF... (and: it's safe to call on NULL packets) */
887
888                 av_free_packet(&anim->next_packet);
889
890                 anim->next_packet.size = 0;
891                 anim->next_packet.data = 0;
892
893                 anim->pFrameComplete = 0;
894
895                 avcodec_decode_video2(
896                         anim->pCodecCtx,
897                         anim->pFrame, &anim->pFrameComplete,
898                         &anim->next_packet);
899
900                 if (anim->pFrameComplete) {
901                         anim->next_pts = av_get_pts_from_frame(
902                                 anim->pFormatCtx, anim->pFrame);
903
904                         av_log(anim->pFormatCtx,
905                                AV_LOG_DEBUG,
906                                "  FRAME DONE (after EOF): next_pts=%lld "
907                                "pkt_pts=%lld, guessed_pts=%lld\n",
908                                (anim->pFrame->pts == AV_NOPTS_VALUE) ?
909                                -1 : (long long int)anim->pFrame->pts,
910                                (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ?
911                                -1 : (long long int)anim->pFrame->pkt_pts,
912                                (long long int)anim->next_pts);
913                         rval = 0;
914                 }
915         }
916
917         if (rval < 0) {
918                 anim->next_packet.stream_index = -1;
919
920                 av_log(anim->pFormatCtx,
921                        AV_LOG_ERROR, "  DECODE READ FAILED: av_read_frame() "
922                        "returned error: %d\n",  rval);
923         }
924
925         return (rval >= 0);
926 }
927
928 static void ffmpeg_decode_video_frame_scan(
929         struct anim *anim, int64_t pts_to_search)
930 {
931         /* there seem to exist *very* silly GOP lengths out in the wild... */
932         int count = 1000;
933
934         av_log(anim->pFormatCtx,
935                AV_LOG_DEBUG,
936                "SCAN start: considering pts=%lld in search of %lld\n",
937                (long long int)anim->next_pts, (long long int)pts_to_search);
938
939         while (count > 0 && anim->next_pts < pts_to_search) {
940                 av_log(anim->pFormatCtx,
941                        AV_LOG_DEBUG,
942                        "  WHILE: pts=%lld in search of %lld\n",
943                        (long long int)anim->next_pts, (long long int)pts_to_search);
944                 if (!ffmpeg_decode_video_frame(anim)) {
945                         break;
946                 }
947                 count--;
948         }
949         if (count == 0) {
950                 av_log(anim->pFormatCtx,
951                        AV_LOG_ERROR,
952                        "SCAN failed: completely lost in stream, "
953                        "bailing out at PTS=%lld, searching for PTS=%lld\n",
954                        (long long int)anim->next_pts, (long long int)pts_to_search);
955         }
956         if (anim->next_pts == pts_to_search) {
957                 av_log(anim->pFormatCtx,
958                        AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
959         }
960         else {
961                 av_log(anim->pFormatCtx,
962                        AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n");
963         }
964 }
965
966 static int match_format(const char *name, AVFormatContext *pFormatCtx)
967 {
968         const char *p;
969         int len, namelen;
970
971         const char *names = pFormatCtx->iformat->name;
972
973         if (!name || !names)
974                 return 0;
975
976         namelen = strlen(name);
977         while ((p = strchr(names, ','))) {
978                 len = MAX2(p - names, namelen);
979                 if (!BLI_strncasecmp(name, names, len))
980                         return 1;
981                 names = p + 1;
982         }
983         return !BLI_strcasecmp(name, names);
984 }
985
986 static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
987 {
988         static const char *byte_seek_list[] = { "mpegts", 0 };
989         const char **p;
990
991         if (pFormatCtx->iformat->flags & AVFMT_TS_DISCONT) {
992                 return true;
993         }
994
995         p = byte_seek_list;
996
997         while (*p) {
998                 if (match_format(*p++, pFormatCtx)) {
999                         return true;
1000                 }
1001         }
1002
1003         return false;
1004 }
1005
1006 static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
1007                                IMB_Timecode_Type tc)
1008 {
1009         int64_t pts_to_search = 0;
1010         double frame_rate;
1011         double pts_time_base;
1012         long long st_time;
1013         struct anim_index *tc_index = 0;
1014         AVStream *v_st;
1015         int new_frame_index = 0; /* To quiet gcc barking... */
1016         int old_frame_index = 0; /* To quiet gcc barking... */
1017
1018         if (anim == NULL) return (0);
1019
1020         av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position);
1021
1022         if (tc != IMB_TC_NONE) {
1023                 tc_index = IMB_anim_open_index(anim, tc);
1024         }
1025
1026         v_st = anim->pFormatCtx->streams[anim->videoStream];
1027
1028         frame_rate = av_q2d(av_get_r_frame_rate_compat(anim->pFormatCtx, v_st));
1029
1030         st_time = anim->pFormatCtx->start_time;
1031         pts_time_base = av_q2d(v_st->time_base);
1032
1033         if (tc_index) {
1034                 new_frame_index = IMB_indexer_get_frame_index(
1035                         tc_index, position);
1036                 old_frame_index = IMB_indexer_get_frame_index(
1037                         tc_index, anim->curposition);
1038                 pts_to_search = IMB_indexer_get_pts(
1039                         tc_index, new_frame_index);
1040         }
1041         else {
1042                 pts_to_search = (long long)
1043                                 floor(((double) position) /
1044                                       pts_time_base / frame_rate + 0.5);
1045
1046                 if (st_time != AV_NOPTS_VALUE) {
1047                         pts_to_search += st_time / pts_time_base / AV_TIME_BASE;
1048                 }
1049         }
1050
1051         av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1052                "FETCH: looking for PTS=%lld "
1053                "(pts_timebase=%g, frame_rate=%g, st_time=%lld)\n",
1054                (long long int)pts_to_search, pts_time_base, frame_rate, st_time);
1055
1056         if (anim->last_frame &&
1057             anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search)
1058         {
1059                 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1060                        "FETCH: frame repeat: last: %lld next: %lld\n",
1061                        (long long int)anim->last_pts,
1062                        (long long int)anim->next_pts);
1063                 IMB_refImBuf(anim->last_frame);
1064                 anim->curposition = position;
1065                 return anim->last_frame;
1066         }
1067
1068         if (position > anim->curposition + 1 &&
1069             anim->preseek &&
1070             !tc_index &&
1071             position - (anim->curposition + 1) < anim->preseek)
1072         {
1073                 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1074                        "FETCH: within preseek interval (no index)\n");
1075
1076                 ffmpeg_decode_video_frame_scan(anim, pts_to_search);
1077         }
1078         else if (tc_index &&
1079                  IMB_indexer_can_scan(tc_index, old_frame_index,
1080                                       new_frame_index))
1081         {
1082                 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1083                        "FETCH: within preseek interval "
1084                        "(index tells us)\n");
1085
1086                 ffmpeg_decode_video_frame_scan(anim, pts_to_search);
1087         }
1088         else if (position != anim->curposition + 1) {
1089                 long long pos;
1090                 int ret;
1091
1092                 if (tc_index) {
1093                         unsigned long long dts;
1094
1095                         pos = IMB_indexer_get_seek_pos(
1096                             tc_index, new_frame_index);
1097                         dts = IMB_indexer_get_seek_pos_dts(
1098                             tc_index, new_frame_index);
1099
1100                         av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1101                                "TC INDEX seek pos = %lld\n", pos);
1102                         av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1103                                "TC INDEX seek dts = %llu\n", dts);
1104
1105                         if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
1106                                 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1107                                        "... using BYTE pos\n");
1108
1109                                 ret = av_seek_frame(anim->pFormatCtx,
1110                                                     -1,
1111                                                     pos, AVSEEK_FLAG_BYTE);
1112                                 av_update_cur_dts(anim->pFormatCtx, v_st, dts);
1113                         }
1114                         else {
1115                                 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1116                                        "... using DTS pos\n");
1117                                 ret = av_seek_frame(anim->pFormatCtx,
1118                                                     anim->videoStream,
1119                                                     dts, AVSEEK_FLAG_BACKWARD);
1120                         }
1121                 }
1122                 else {
1123                         pos = (long long) (position - anim->preseek) *
1124                               AV_TIME_BASE / frame_rate;
1125
1126                         av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1127                                "NO INDEX seek pos = %lld, st_time = %lld\n",
1128                                pos, (st_time != AV_NOPTS_VALUE) ? st_time : 0);
1129
1130                         if (pos < 0) {
1131                                 pos = 0;
1132                         }
1133
1134                         if (st_time != AV_NOPTS_VALUE) {
1135                                 pos += st_time;
1136                         }
1137
1138                         av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1139                                "NO INDEX final seek pos = %lld\n", pos);
1140
1141                         ret = av_seek_frame(anim->pFormatCtx, -1,
1142                                             pos, AVSEEK_FLAG_BACKWARD);
1143                 }
1144
1145                 if (ret < 0) {
1146                         av_log(anim->pFormatCtx, AV_LOG_ERROR,
1147                                "FETCH: "
1148                                "error while seeking to DTS = %lld "
1149                                "(frameno = %d, PTS = %lld): errcode = %d\n",
1150                                pos, position, (long long int)pts_to_search, ret);
1151                 }
1152
1153                 avcodec_flush_buffers(anim->pCodecCtx);
1154
1155                 anim->next_pts = -1;
1156
1157                 if (anim->next_packet.stream_index == anim->videoStream) {
1158                         av_free_packet(&anim->next_packet);
1159                         anim->next_packet.stream_index = -1;
1160                 }
1161
1162                 /* memset(anim->pFrame, ...) ?? */
1163
1164                 if (ret >= 0) {
1165                         ffmpeg_decode_video_frame_scan(anim, pts_to_search);
1166                 }
1167         }
1168         else if (position == 0 && anim->curposition == -1) {
1169                 /* first frame without seeking special case... */
1170                 ffmpeg_decode_video_frame(anim);
1171         }
1172         else {
1173                 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
1174                        "FETCH: no seek necessary, just continue...\n");
1175         }
1176
1177         IMB_freeImBuf(anim->last_frame);
1178         anim->last_frame = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
1179         anim->last_frame->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);
1180
1181         ffmpeg_postprocess(anim);
1182
1183         anim->last_pts = anim->next_pts;
1184
1185         ffmpeg_decode_video_frame(anim);
1186
1187         anim->curposition = position;
1188
1189         IMB_refImBuf(anim->last_frame);
1190
1191         return anim->last_frame;
1192 }
1193
1194 static void free_anim_ffmpeg(struct anim *anim)
1195 {
1196         if (anim == NULL) return;
1197
1198         if (anim->pCodecCtx) {
1199                 avcodec_close(anim->pCodecCtx);
1200                 avformat_close_input(&anim->pFormatCtx);
1201
1202                 /* Special case here: pFrame could share pointers with codec,
1203                  * so in order to avoid double-free we don't use av_frame_free()
1204                  * to free the frame.
1205                  *
1206                  * Could it be a bug in FFmpeg?
1207                  */
1208                 av_free(anim->pFrame);
1209
1210                 if (!need_aligned_ffmpeg_buffer(anim)) {
1211                         /* If there's no need for own aligned buffer it means that FFmpeg's
1212                          * frame shares the same buffer as temporary ImBuf. In this case we
1213                          * should not free the buffer when freeing the FFmpeg buffer.
1214                          */
1215                         avpicture_fill((AVPicture *)anim->pFrameRGB,
1216                                        NULL,
1217                                        AV_PIX_FMT_RGBA,
1218                                        anim->x, anim->y);
1219                 }
1220                 av_frame_free(&anim->pFrameRGB);
1221                 av_frame_free(&anim->pFrameDeinterlaced);
1222
1223                 sws_freeContext(anim->img_convert_ctx);
1224                 IMB_freeImBuf(anim->last_frame);
1225                 if (anim->next_packet.stream_index != -1) {
1226                         av_free_packet(&anim->next_packet);
1227                 }
1228         }
1229         anim->duration = 0;
1230 }
1231
1232 #endif
1233
1234 /* Try next picture to read */
1235 /* No picture, try to open next animation */
1236 /* Succeed, remove first image from animation */
1237
1238 static ImBuf *anim_getnew(struct anim *anim)
1239 {
1240         struct ImBuf *ibuf = NULL;
1241
1242         if (anim == NULL) return(NULL);
1243
1244         free_anim_movie(anim);
1245
1246 #ifdef WITH_AVI
1247         free_anim_avi(anim);
1248 #endif
1249
1250 #ifdef WITH_FFMPEG
1251         free_anim_ffmpeg(anim);
1252 #endif
1253
1254         if (anim->curtype != 0) return (NULL);
1255         anim->curtype = imb_get_anim_type(anim->name);
1256
1257         switch (anim->curtype) {
1258                 case ANIM_SEQUENCE:
1259                         ibuf = IMB_loadiffname(anim->name, anim->ib_flags, anim->colorspace);
1260                         if (ibuf) {
1261                                 BLI_strncpy(anim->first, anim->name, sizeof(anim->first));
1262                                 anim->duration = 1;
1263                         }
1264                         break;
1265                 case ANIM_MOVIE:
1266                         if (startmovie(anim)) return (NULL);
1267                         ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0); /* fake */
1268                         break;
1269 #ifdef WITH_AVI
1270                 case ANIM_AVI:
1271                         if (startavi(anim)) {
1272                                 printf("couldn't start avi\n");
1273                                 return (NULL);
1274                         }
1275                         ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
1276                         break;
1277 #endif
1278 #ifdef WITH_FFMPEG
1279                 case ANIM_FFMPEG:
1280                         if (startffmpeg(anim)) return (0);
1281                         ibuf = IMB_allocImBuf(anim->x, anim->y, 24, 0);
1282                         break;
1283 #endif
1284         }
1285         return(ibuf);
1286 }
1287
1288 struct ImBuf *IMB_anim_previewframe(struct anim *anim)
1289 {
1290         struct ImBuf *ibuf = NULL;
1291         int position = 0;
1292
1293         ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
1294         if (ibuf) {
1295                 IMB_freeImBuf(ibuf);
1296                 position = anim->duration / 2;
1297                 ibuf = IMB_anim_absolute(anim, position, IMB_TC_NONE,
1298                                          IMB_PROXY_NONE);
1299         }
1300         return ibuf;
1301 }
1302
1303 struct ImBuf *IMB_anim_absolute(struct anim *anim, int position,
1304                                 IMB_Timecode_Type tc,
1305                                 IMB_Proxy_Size preview_size)
1306 {
1307         struct ImBuf *ibuf = NULL;
1308         char head[256], tail[256];
1309         unsigned short digits;
1310         int pic;
1311         int filter_y;
1312         if (anim == NULL) return(NULL);
1313
1314         filter_y = (anim->ib_flags & IB_animdeinterlace);
1315
1316         if (preview_size == IMB_PROXY_NONE) {
1317                 if (anim->curtype == 0) {
1318                         ibuf = anim_getnew(anim);
1319                         if (ibuf == NULL) {
1320                                 return(NULL);
1321                         }
1322
1323                         IMB_freeImBuf(ibuf); /* ???? */
1324                         ibuf = NULL;
1325                 }
1326
1327                 if (position < 0) return(NULL);
1328                 if (position >= anim->duration) return(NULL);
1329         }
1330         else {
1331                 struct anim *proxy = IMB_anim_open_proxy(anim, preview_size);
1332
1333                 if (proxy) {
1334                         position = IMB_anim_index_get_frame_index(
1335                             anim, tc, position);
1336
1337                         return IMB_anim_absolute(
1338                                    proxy, position,
1339                                    IMB_TC_NONE, IMB_PROXY_NONE);
1340                 }
1341         }
1342
1343         switch (anim->curtype) {
1344                 case ANIM_SEQUENCE:
1345                         pic = an_stringdec(anim->first, head, tail, &digits);
1346                         pic += position;
1347                         an_stringenc(anim->name, head, tail, digits, pic);
1348                         ibuf = IMB_loadiffname(anim->name, IB_rect, anim->colorspace);
1349                         if (ibuf) {
1350                                 anim->curposition = position;
1351                         }
1352                         break;
1353                 case ANIM_MOVIE:
1354                         ibuf = movie_fetchibuf(anim, position);
1355                         if (ibuf) {
1356                                 anim->curposition = position;
1357                                 IMB_convert_rgba_to_abgr(ibuf);
1358                         }
1359                         break;
1360 #ifdef WITH_AVI
1361                 case ANIM_AVI:
1362                         ibuf = avi_fetchibuf(anim, position);
1363                         if (ibuf)
1364                                 anim->curposition = position;
1365                         break;
1366 #endif
1367 #ifdef WITH_FFMPEG
1368                 case ANIM_FFMPEG:
1369                         ibuf = ffmpeg_fetchibuf(anim, position, tc);
1370                         if (ibuf)
1371                                 anim->curposition = position;
1372                         filter_y = 0; /* done internally */
1373                         break;
1374 #endif
1375         }
1376
1377         if (ibuf) {
1378                 if (filter_y) IMB_filtery(ibuf);
1379                 BLI_snprintf(ibuf->name, sizeof(ibuf->name), "%s.%04d", anim->name, anim->curposition + 1);
1380
1381         }
1382         return(ibuf);
1383 }
1384
1385 /***/
1386
1387 int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc)
1388 {
1389         struct anim_index *idx;
1390         if (tc == IMB_TC_NONE) {
1391                 return anim->duration;
1392         }
1393
1394         idx = IMB_anim_open_index(anim, tc);
1395         if (!idx) {
1396                 return anim->duration;
1397         }
1398
1399         return IMB_indexer_get_duration(idx);
1400 }
1401
1402 bool IMB_anim_get_fps(struct anim *anim,
1403                      short *frs_sec, float *frs_sec_base, bool no_av_base)
1404 {
1405         double frs_sec_base_double;
1406         if (anim->frs_sec) {
1407                 if (anim->frs_sec > SHRT_MAX) {
1408                         /* We cannot store original rational in our short/float format,
1409                          * we need to approximate it as best as we can... */
1410                         *frs_sec = SHRT_MAX;
1411                         frs_sec_base_double = anim->frs_sec_base * (double)SHRT_MAX / (double)anim->frs_sec;
1412                 }
1413                 else {
1414                         *frs_sec = anim->frs_sec;
1415                         frs_sec_base_double = anim->frs_sec_base;
1416                 }
1417 #ifdef WITH_FFMPEG
1418                 if (no_av_base) {
1419                         *frs_sec_base = (float)(frs_sec_base_double / AV_TIME_BASE);
1420                 }
1421                 else {
1422                         *frs_sec_base = (float)frs_sec_base_double;
1423                 }
1424 #else
1425                 UNUSED_VARS(no_av_base);
1426                 *frs_sec_base = (float)frs_sec_base_double;
1427 #endif
1428                 BLI_assert(*frs_sec > 0);
1429                 BLI_assert(*frs_sec_base > 0.0f);
1430
1431                 return true;
1432         }
1433         return false;
1434 }
1435
1436 void IMB_anim_set_preseek(struct anim *anim, int preseek)
1437 {
1438         anim->preseek = preseek;
1439 }
1440
1441 int IMB_anim_get_preseek(struct anim *anim)
1442 {
1443         return anim->preseek;
1444 }