Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/imbuf/intern/anim_movie.c')
-rw-r--r--source/blender/imbuf/intern/anim_movie.c566
1 files changed, 429 insertions, 137 deletions
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 8b0104fcdca..7b172008bee 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -57,6 +57,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
+#include <math.h>
#ifndef _WIN32
#include <dirent.h>
#else
@@ -66,6 +67,7 @@
#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail
BLI_countlist BLI_stringdec */
#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
#include "MEM_guardedalloc.h"
@@ -90,6 +92,7 @@
#include "IMB_allocimbuf.h"
#include "IMB_anim.h"
+#include "IMB_indexer.h"
#ifdef WITH_FFMPEG
#include <libavformat/avformat.h>
@@ -304,15 +307,6 @@ static void free_anim_avi (struct anim *anim) {
anim->duration = 0;
}
-void IMB_free_anim_ibuf(struct anim * anim) {
- if (anim == NULL) return;
-
- if (anim->ibuf1) IMB_freeImBuf(anim->ibuf1);
- if (anim->ibuf2) IMB_freeImBuf(anim->ibuf2);
-
- anim->ibuf1 = anim->ibuf2 = NULL;
-}
-
#ifdef WITH_FFMPEG
static void free_anim_ffmpeg(struct anim * anim);
#endif
@@ -326,7 +320,6 @@ void IMB_free_anim(struct anim * anim) {
return;
}
- IMB_free_anim_ibuf(anim);
free_anim_movie(anim);
free_anim_avi(anim);
@@ -339,6 +332,7 @@ void IMB_free_anim(struct anim * anim) {
#ifdef WITH_REDCODE
free_anim_redcode(anim);
#endif
+ IMB_free_indices(anim);
MEM_freeN(anim);
}
@@ -350,13 +344,14 @@ void IMB_close_anim(struct anim * anim) {
}
-struct anim * IMB_open_anim( const char * name, int ib_flags) {
+struct anim * IMB_open_anim( const char * name, int ib_flags, int streamindex) {
struct anim * anim;
anim = (struct anim*)MEM_callocN(sizeof(struct anim), "anim struct");
if (anim != NULL) {
BLI_strncpy(anim->name, name, sizeof(anim->name));
anim->ib_flags = ib_flags;
+ anim->streamindex = streamindex;
}
return(anim);
}
@@ -368,10 +363,13 @@ static int startavi (struct anim *anim) {
#if defined(_WIN32) && !defined(FREE_WINDOWS)
HRESULT hr;
int i, firstvideo = -1;
+ int streamcount;
BYTE abFormat[1024];
LONG l;
LPBITMAPINFOHEADER lpbi;
AVISTREAMINFO avis;
+
+ streamcount = anim->streamindex;
#endif
anim->avi = MEM_callocN (sizeof(AviMovie),"animavi");
@@ -396,6 +394,10 @@ static int startavi (struct anim *anim) {
AVIStreamInfo(anim->pavi[i], &avis, sizeof(avis));
if ((avis.fccType == streamtypeVIDEO) && (firstvideo == -1)) {
+ if (streamcount > 0) {
+ streamcount--;
+ continue;
+ }
anim->pgf = AVIStreamGetFrameOpen(anim->pavi[i], NULL);
if (anim->pgf) {
firstvideo = i;
@@ -496,14 +498,14 @@ static ImBuf * avi_fetchibuf (struct anim *anim, int position) {
for (y=0; y < anim->y; y++) {
memcpy (&(ibuf->rect)[((anim->y-y)-1)*anim->x], &tmp[y*anim->x],
- anim->x * 4);
+ anim->x * 4);
}
MEM_freeN (tmp);
}
-
+
ibuf->profile = IB_PROFILE_SRGB;
-
+
return ibuf;
}
@@ -517,6 +519,9 @@ static int startffmpeg(struct anim * anim) {
AVCodec *pCodec;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
+ int frs_num;
+ double frs_den;
+ int streamcount;
#ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
/* The following for color space determination */
@@ -527,6 +532,8 @@ static int startffmpeg(struct anim * anim) {
if (anim == 0) return(-1);
+ streamcount = anim->streamindex;
+
do_init_ffmpeg();
if(av_open_input_file(&pFormatCtx, anim->name, NULL, 0, NULL)!=0) {
@@ -541,12 +548,17 @@ static int startffmpeg(struct anim * anim) {
av_dump_format(pFormatCtx, 0, anim->name, 0);
- /* Find the first video stream */
- videoStream=-1;
- for(i=0; i<pFormatCtx->nb_streams; i++)
- if(pFormatCtx->streams[i]->codec->codec_type
+ /* Find the video stream */
+ videoStream = -1;
+
+ for(i = 0; i < pFormatCtx->nb_streams; i++)
+ if (pFormatCtx->streams[i]->codec->codec_type
== AVMEDIA_TYPE_VIDEO) {
- videoStream=i;
+ if (streamcount > 0) {
+ streamcount--;
+ continue;
+ }
+ videoStream = i;
break;
}
@@ -557,16 +569,16 @@ static int startffmpeg(struct anim * anim) {
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
- /* Find the decoder for the video stream */
- pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
- if(pCodec==NULL) {
+ /* Find the decoder for the video stream */
+ pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
+ if(pCodec == NULL) {
av_close_input_file(pFormatCtx);
return -1;
}
pCodecCtx->workaround_bugs = 1;
- if(avcodec_open(pCodecCtx, pCodec)<0) {
+ if(avcodec_open(pCodecCtx, pCodec) < 0) {
av_close_input_file(pFormatCtx);
return -1;
}
@@ -575,6 +587,19 @@ static int startffmpeg(struct anim * anim) {
* av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)
/ AV_TIME_BASE);
+ frs_num = pFormatCtx->streams[videoStream]->r_frame_rate.num;
+ frs_den = pFormatCtx->streams[videoStream]->r_frame_rate.den;
+
+ frs_den *= AV_TIME_BASE;
+
+ while (frs_num % 10 == 0 && frs_den >= 2.0 && frs_num > 10) {
+ frs_num /= 10;
+ frs_den /= 10;
+ }
+
+ anim->frs_sec = frs_num;
+ anim->frs_sec_base = frs_den;
+
anim->params = 0;
anim->x = pCodecCtx->width;
@@ -584,6 +609,11 @@ static int startffmpeg(struct anim * anim) {
anim->framesize = anim->x * anim->y * 4;
anim->curposition = -1;
+ anim->last_frame = 0;
+ anim->last_pts = -1;
+ anim->next_pts = -1;
+ anim->next_undecoded_pts = -1;
+ anim->next_packet.stream_index = -1;
anim->pFormatCtx = pFormatCtx;
anim->pCodecCtx = pCodecCtx;
@@ -666,10 +696,19 @@ static int startffmpeg(struct anim * anim) {
return (0);
}
-static void ffmpeg_postprocess(struct anim * anim, ImBuf * ibuf,
- int * filter_y)
+/* postprocess the image in anim->pFrame and do color conversion
+ and deinterlacing stuff.
+
+ Output is anim->last_frame
+*/
+
+static void ffmpeg_postprocess(struct anim * anim)
{
AVFrame * input = anim->pFrame;
+ ImBuf * ibuf = anim->last_frame;
+ int filter_y = 0;
+
+ ibuf->profile = IB_PROFILE_SRGB;
/* This means the data wasnt read properly,
this check stops crashing */
@@ -690,12 +729,16 @@ static void ffmpeg_postprocess(struct anim * anim, ImBuf * ibuf,
anim->pCodecCtx->width,
anim->pCodecCtx->height)
< 0) {
- *filter_y = 1;
+ filter_y = TRUE;
} else {
input = anim->pFrameDeinterlaced;
}
}
+ avpicture_fill((AVPicture*) anim->pFrameRGB,
+ (unsigned char*) ibuf->rect,
+ PIX_FMT_RGBA, anim->x, anim->y);
+
if (ENDIAN_ORDER == B_ENDIAN) {
int * dstStride = anim->pFrameRGB->linesize;
uint8_t** dst = anim->pFrameRGB->data;
@@ -774,150 +817,359 @@ static void ffmpeg_postprocess(struct anim * anim, ImBuf * ibuf,
}
}
}
+
+ if (filter_y) {
+ IMB_filtery(ibuf);
+ }
}
-static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
- ImBuf * ibuf;
- int frameFinished;
- AVPacket packet;
+/* decode one video frame and load the next packet into anim->packet,
+ so that we can obtain next_pts and next undecoded pts */
+
+static int ffmpeg_decode_video_frame(struct anim * anim)
+{
+ int frameFinished = 0;
+ int rval = 0;
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
+
+ anim->next_undecoded_pts = -1;
+
+ if (anim->next_packet.stream_index == anim->videoStream) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ " DECODE: cached next packet\n");
+
+ avcodec_decode_video2(anim->pCodecCtx,
+ anim->pFrame, &frameFinished,
+ &anim->next_packet);
+
+ if (frameFinished) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME DONE: "
+ "next_pts=%lld pkt_pts=%lld\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pts,
+ (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pkt_pts);
+ anim->next_pts =
+ av_get_pts_from_frame(anim->pFormatCtx,
+ anim->pFrame);
+ }
+
+ av_free_packet(&anim->next_packet);
+ anim->next_packet.stream_index = -1;
+ }
+
+ while((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ "%sREAD: strID=%d (VID: %d) dts=%lld pts=%lld "
+ "%s\n",
+ (anim->next_packet.stream_index == anim->videoStream)
+ ? "->" : " ",
+ anim->next_packet.stream_index,
+ anim->videoStream,
+ (anim->next_packet.dts == AV_NOPTS_VALUE) ? -1:
+ anim->next_packet.dts,
+ (anim->next_packet.pts == AV_NOPTS_VALUE) ? -1:
+ anim->next_packet.pts,
+ (anim->next_packet.flags & AV_PKT_FLAG_KEY) ?
+ " KEY" : "");
+ if (anim->next_packet.stream_index == anim->videoStream) {
+ if (frameFinished) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME finished, we leave\n");
+ anim->next_undecoded_pts
+ = anim->next_packet.dts;
+ break;
+ }
+
+ avcodec_decode_video2(
+ anim->pCodecCtx,
+ anim->pFrame, &frameFinished,
+ &anim->next_packet);
+
+ if (frameFinished) {
+ anim->next_pts = av_get_pts_from_frame(
+ anim->pFormatCtx, anim->pFrame);
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " FRAME DONE: next_pts=%lld "
+ "pkt_pts=%lld, guessed_pts=%lld\n",
+ (anim->pFrame->pts == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pts,
+ (anim->pFrame->pkt_pts
+ == AV_NOPTS_VALUE) ?
+ -1 : anim->pFrame->pkt_pts,
+ anim->next_pts);
+ }
+ }
+ av_free_packet(&anim->next_packet);
+ anim->next_packet.stream_index = -1;
+ }
+
+ if (rval < 0) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_ERROR, " DECODE READ FAILED: av_read_frame() "
+ "returned error: %d\n", rval);
+ }
+ return (rval >= 0);
+}
+
+static void ffmpeg_decode_video_frame_scan(
+ struct anim * anim, int64_t pts_to_search)
+{
+ /* there seem to exist *very* silly GOP lengths out in the wild... */
+ int count = 1000;
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ "SCAN start: considering pts=%lld in search of %lld\n",
+ anim->next_pts, pts_to_search);
+
+ while (count > 0 && anim->next_pts < pts_to_search) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " WHILE: pts=%lld in search of %lld\n",
+ anim->next_pts, pts_to_search);
+ if (!ffmpeg_decode_video_frame(anim)) {
+ break;
+ }
+ count--;
+ }
+ if (count == 0) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_ERROR,
+ "SCAN failed: completely lost in stream, "
+ "bailing out at PTS=%lld, searching for PTS=%lld\n",
+ anim->next_pts, pts_to_search);
+ }
+ if (anim->next_pts == pts_to_search) {
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
+ } else {
+ av_log(anim->pFormatCtx,
+ AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n");
+ }
+}
+
+static int match_format(const char *name, AVFormatContext * pFormatCtx)
+{
+ const char *p;
+ int len, namelen;
+
+ const char *names = pFormatCtx->iformat->name;
+
+ if (!name || !names)
+ return 0;
+
+ namelen = strlen(name);
+ while ((p = strchr(names, ','))) {
+ len = MAX2(p - names, namelen);
+ if (!BLI_strncasecmp(name, names, len))
+ return 1;
+ names = p+1;
+ }
+ return !BLI_strcasecmp(name, names);
+}
+
+static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
+{
+ static const char * byte_seek_list [] = { "dv", "mpegts", 0 };
+ const char ** p;
+
+ if (pFormatCtx->iformat->flags & AVFMT_TS_DISCONT) {
+ return TRUE;
+ }
+
+ p = byte_seek_list;
+
+ while (*p) {
+ if (match_format(*p++, pFormatCtx)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position,
+ IMB_Timecode_Type tc) {
int64_t pts_to_search = 0;
- int pos_found = 1;
- int filter_y = 0;
- int seek_by_bytes= 0;
- int preseek_count = 0;
+ double frame_rate;
+ double pts_time_base;
+ long long st_time;
+ struct anim_index * tc_index = 0;
+ AVStream * v_st;
+ int new_frame_index;
+ int old_frame_index;
if (anim == 0) return (0);
- ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position);
- avpicture_fill((AVPicture*) anim->pFrameRGB,
- (unsigned char*) ibuf->rect,
- PIX_FMT_RGBA, anim->x, anim->y);
-
- if (position != anim->curposition + 1) {
- if (position > anim->curposition + 1
- && anim->preseek
- && position - (anim->curposition + 1) < anim->preseek) {
- while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
- if (packet.stream_index == anim->videoStream) {
- avcodec_decode_video2(
- anim->pCodecCtx,
- anim->pFrame, &frameFinished,
- &packet);
-
- if (frameFinished) {
- anim->curposition++;
- }
- }
- av_free_packet(&packet);
- if (position == anim->curposition+1) {
- break;
- }
- }
+ if (tc != IMB_TC_NONE) {
+ tc_index = IMB_anim_open_index(anim, tc);
+ }
+
+ v_st = anim->pFormatCtx->streams[anim->videoStream];
+
+ frame_rate = av_q2d(v_st->r_frame_rate);
+
+ st_time = anim->pFormatCtx->start_time;
+ pts_time_base = av_q2d(v_st->time_base);
+
+ if (tc_index) {
+ new_frame_index = IMB_indexer_get_frame_index(
+ tc_index, position);
+ old_frame_index = IMB_indexer_get_frame_index(
+ tc_index, anim->curposition);
+ pts_to_search = IMB_indexer_get_pts(
+ tc_index, new_frame_index);
+ } else {
+ pts_to_search = (long long)
+ floor(((double) position) / pts_time_base / frame_rate + 0.5);
+
+ if (st_time != AV_NOPTS_VALUE) {
+ pts_to_search += st_time / pts_time_base
+ / AV_TIME_BASE;
}
}
-/* disable seek_by_bytes for now, since bitrates are guessed wrong!
- also: MPEG2TS-seeking was fixed in later versions of ffmpeg, so problem
- is somewhat fixed by now (until we add correct timecode management code...)
-*/
-#if 0
- seek_by_bytes = !!(anim->pFormatCtx->iformat->flags & AVFMT_TS_DISCONT);
-#else
- seek_by_bytes = FALSE;
-#endif
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: looking for PTS=%lld "
+ "(pts_timebase=%g, frame_rate=%g, st_time=%lld)\n",
+ pts_to_search, pts_time_base, frame_rate, st_time);
+
+ if (anim->last_frame &&
+ anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search){
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: frame repeat: last: %lld next: %lld\n",
+ anim->last_pts, anim->next_pts);
+ IMB_refImBuf(anim->last_frame);
+ anim->curposition = position;
+ return anim->last_frame;
+ }
+
+ IMB_freeImBuf(anim->last_frame);
+
+ if (anim->next_pts <= pts_to_search &&
+ anim->next_undecoded_pts > pts_to_search) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: no seek necessary: "
+ "next: %lld next undecoded: %lld\n",
+ anim->next_pts, anim->next_undecoded_pts);
+
+ /* we are already done :) */
+
+ } else if (position > anim->curposition + 1
+ && anim->preseek
+ && !tc_index
+ && position - (anim->curposition + 1) < anim->preseek) {
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: within preseek interval (no index)\n");
+
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
+ } else if (tc_index &&
+ IMB_indexer_can_scan(tc_index, old_frame_index,
+ new_frame_index)) {
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "FETCH: within preseek interval "
+ "(index tells us)\n");
- if (position != anim->curposition + 1) {
- double frame_rate =
- av_q2d(anim->pFormatCtx->streams[anim->videoStream]
- ->r_frame_rate);
- double pts_time_base = av_q2d(anim->pFormatCtx->streams[anim->videoStream]->time_base);
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
+ } else if (position != anim->curposition + 1) {
long long pos;
- long long st_time = anim->pFormatCtx->start_time;
int ret;
- if (seek_by_bytes) {
- pos = position - anim->preseek;
- if (pos < 0) {
- pos = 0;
- }
- preseek_count = position - pos;
+ if (tc_index) {
+ unsigned long long dts;
+
+ pos = IMB_indexer_get_seek_pos(
+ tc_index, new_frame_index);
+ dts = IMB_indexer_get_seek_pos_dts(
+ tc_index, new_frame_index);
+
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "TC INDEX seek pos = %lld\n", pos);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "TC INDEX seek dts = %lld\n", dts);
- pos *= anim->pFormatCtx->bit_rate / frame_rate;
- pos /= 8;
+ if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "... using BYTE pos\n");
+
+ ret = av_seek_frame(anim->pFormatCtx,
+ -1,
+ pos, AVSEEK_FLAG_BYTE);
+ av_update_cur_dts(anim->pFormatCtx, v_st, dts);
+ } else {
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG,
+ "... using DTS pos\n");
+ ret = av_seek_frame(anim->pFormatCtx,
+ anim->videoStream,
+ dts, AVSEEK_FLAG_BACKWARD);
+ }
} else {
pos = (long long) (position - anim->preseek)
* AV_TIME_BASE / frame_rate;
if (pos < 0) {
pos = 0;
}
-
+
if (st_time != AV_NOPTS_VALUE) {
pos += st_time;
}
- }
- ret = av_seek_frame(anim->pFormatCtx, -1,
- pos,
- AVSEEK_FLAG_BACKWARD | (
- seek_by_bytes
- ? AVSEEK_FLAG_ANY
- | AVSEEK_FLAG_BYTE : 0));
- if (ret < 0) {
- fprintf(stderr, "error while seeking: %d\n", ret);
+ ret = av_seek_frame(anim->pFormatCtx, -1,
+ pos, AVSEEK_FLAG_BACKWARD);
}
- pts_to_search = (long long)
- (((double) position) / pts_time_base / frame_rate);
- if (st_time != AV_NOPTS_VALUE) {
- pts_to_search += st_time / pts_time_base/ AV_TIME_BASE;
+ if (ret < 0) {
+ av_log(anim->pFormatCtx, AV_LOG_ERROR,
+ "FETCH: "
+ "error while seeking to DTS = %lld "
+ "(frameno = %d, PTS = %lld): errcode = %d\n",
+ pos, position, pts_to_search, ret);
}
- pos_found = 0;
avcodec_flush_buffers(anim->pCodecCtx);
- }
- while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
- if(packet.stream_index == anim->videoStream) {
- avcodec_decode_video2(anim->pCodecCtx,
- anim->pFrame, &frameFinished,
- &packet);
+ anim->next_pts = -1;
- if (seek_by_bytes && preseek_count > 0) {
- preseek_count--;
- }
+ if (anim->next_packet.stream_index == anim->videoStream) {
+ av_free_packet(&anim->next_packet);
+ anim->next_packet.stream_index = -1;
+ }
- if (frameFinished && !pos_found) {
- if (seek_by_bytes) {
- if (!preseek_count) {
- pos_found = 1;
- anim->curposition = position;
- }
- } else {
- if (packet.dts >= pts_to_search) {
- pos_found = 1;
- anim->curposition = position;
- }
- }
- }
+ /* memset(anim->pFrame,...) ?? */
- if(frameFinished && pos_found == 1) {
- ffmpeg_postprocess(anim, ibuf, &filter_y);
- av_free_packet(&packet);
- break;
- }
+ if (ret >= 0) {
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
}
-
- av_free_packet(&packet);
+ } else if (position == 0 && anim->curposition == -1) {
+ /* first frame without seeking special case... */
+ ffmpeg_decode_video_frame(anim);
}
- if (filter_y && ibuf) {
- IMB_filtery(ibuf);
- }
+ anim->last_frame = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
- ibuf->profile = IB_PROFILE_SRGB;
+ ffmpeg_postprocess(anim);
- return(ibuf);
+ anim->last_pts = anim->next_pts;
+
+ ffmpeg_decode_video_frame(anim);
+
+ anim->curposition = position;
+
+ IMB_refImBuf(anim->last_frame);
+
+ return anim->last_frame;
}
static void free_anim_ffmpeg(struct anim * anim) {
@@ -934,6 +1186,10 @@ static void free_anim_ffmpeg(struct anim * anim) {
}
av_free(anim->pFrameDeinterlaced);
sws_freeContext(anim->img_convert_ctx);
+ IMB_freeImBuf(anim->last_frame);
+ if (anim->next_packet.stream_index != -1) {
+ av_free_packet(&anim->next_packet);
+ }
}
anim->duration = 0;
}
@@ -1063,16 +1319,19 @@ struct ImBuf * IMB_anim_previewframe(struct anim * anim) {
struct ImBuf * ibuf = NULL;
int position = 0;
- ibuf = IMB_anim_absolute(anim, 0);
+ ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
if (ibuf) {
IMB_freeImBuf(ibuf);
position = anim->duration / 2;
- ibuf = IMB_anim_absolute(anim, position);
+ ibuf = IMB_anim_absolute(anim, position, IMB_TC_NONE,
+ IMB_PROXY_NONE);
}
return ibuf;
}
-struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
+struct ImBuf * IMB_anim_absolute(struct anim * anim, int position,
+ IMB_Timecode_Type tc,
+ IMB_Proxy_Size preview_size) {
struct ImBuf * ibuf = NULL;
char head[256], tail[256];
unsigned short digits;
@@ -1095,6 +1354,18 @@ struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
if (position < 0) return(NULL);
if (position >= anim->duration) return(NULL);
+ if (preview_size != IMB_PROXY_NONE) {
+ struct anim * proxy = IMB_anim_open_proxy(anim, preview_size);
+
+ if (proxy) {
+ position = IMB_anim_index_get_frame_index(
+ anim, tc, position);
+ return IMB_anim_absolute(
+ proxy, position,
+ IMB_TC_NONE, IMB_PROXY_NONE);
+ }
+ }
+
switch(anim->curtype) {
case ANIM_SEQUENCE:
pic = an_stringdec(anim->first, head, tail, &digits);
@@ -1127,7 +1398,7 @@ struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
#endif
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- ibuf = ffmpeg_fetchibuf(anim, position);
+ ibuf = ffmpeg_fetchibuf(anim, position, tc);
if (ibuf)
anim->curposition = position;
filter_y = 0; /* done internally */
@@ -1151,8 +1422,29 @@ struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
/***/
-int IMB_anim_get_duration(struct anim *anim) {
- return anim->duration;
+int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) {
+ struct anim_index * idx;
+ if (tc == IMB_TC_NONE) {
+ return anim->duration;
+ }
+
+ idx = IMB_anim_open_index(anim, tc);
+ if (!idx) {
+ return anim->duration;
+ }
+
+ return IMB_indexer_get_duration(idx);
+}
+
+int IMB_anim_get_fps(struct anim * anim,
+ short * frs_sec, float * frs_sec_base)
+{
+ if (anim->frs_sec) {
+ *frs_sec = anim->frs_sec;
+ *frs_sec_base = anim->frs_sec_base;
+ return TRUE;
+ }
+ return FALSE;
}
void IMB_anim_set_preseek(struct anim * anim, int preseek)