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