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.c362
1 files changed, 190 insertions, 172 deletions
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 5918a4bf16e..622b6cbfc16 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -433,8 +433,7 @@ static int startavi(struct anim *anim)
anim->orientation = 0;
anim->framesize = anim->x * anim->y * 4;
- anim->curposition = 0;
- anim->preseek = 0;
+ anim->cur_position = 0;
# if 0
printf("x:%d y:%d size:%d interl:%d dur:%d\n",
@@ -650,12 +649,12 @@ static int startffmpeg(struct anim *anim)
anim->orientation = 0;
anim->framesize = anim->x * anim->y * 4;
- anim->curposition = -1;
- anim->last_frame = 0;
- anim->last_pts = -1;
- anim->next_pts = -1;
- anim->next_packet = av_packet_alloc();
- anim->next_packet->stream_index = -1;
+ anim->cur_position = -1;
+ anim->cur_frame_final = 0;
+ anim->cur_pts = -1;
+ anim->cur_key_frame_pts = -1;
+ anim->cur_packet = av_packet_alloc();
+ anim->cur_packet->stream_index = -1;
anim->pFrame = av_frame_alloc();
anim->pFrameComplete = false;
@@ -671,7 +670,7 @@ static int startffmpeg(struct anim *anim)
fprintf(stderr, "Could not allocate frame data.\n");
avcodec_free_context(&anim->pCodecCtx);
avformat_close_input(&anim->pFormatCtx);
- av_packet_free(&anim->next_packet);
+ av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
av_frame_free(&anim->pFrame);
@@ -684,7 +683,7 @@ static int startffmpeg(struct anim *anim)
fprintf(stderr, "ffmpeg has changed alloc scheme ... ARGHHH!\n");
avcodec_free_context(&anim->pCodecCtx);
avformat_close_input(&anim->pFormatCtx);
- av_packet_free(&anim->next_packet);
+ av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
av_frame_free(&anim->pFrame);
@@ -706,20 +705,13 @@ static int startffmpeg(struct anim *anim)
1);
}
- if (pCodecCtx->has_b_frames) {
- anim->preseek = 25; /* FIXME: detect gopsize ... */
- }
- else {
- anim->preseek = 0;
- }
-
anim->img_convert_ctx = sws_getContext(anim->x,
anim->y,
anim->pCodecCtx->pix_fmt,
anim->x,
anim->y,
AV_PIX_FMT_RGBA,
- SWS_FAST_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
+ SWS_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
NULL,
NULL,
NULL);
@@ -728,7 +720,7 @@ static int startffmpeg(struct anim *anim)
fprintf(stderr, "Can't transform color space??? Bailing out...\n");
avcodec_free_context(&anim->pCodecCtx);
avformat_close_input(&anim->pFormatCtx);
- av_packet_free(&anim->next_packet);
+ av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
av_frame_free(&anim->pFrame);
@@ -769,13 +761,13 @@ static int startffmpeg(struct anim *anim)
/* postprocess the image in anim->pFrame and do color conversion
* and deinterlacing stuff.
*
- * Output is anim->last_frame
+ * Output is anim->cur_frame_final
*/
static void ffmpeg_postprocess(struct anim *anim)
{
AVFrame *input = anim->pFrame;
- ImBuf *ibuf = anim->last_frame;
+ ImBuf *ibuf = anim->cur_frame_final;
int filter_y = 0;
if (!anim->pFrameComplete) {
@@ -902,7 +894,7 @@ static void ffmpeg_postprocess(struct anim *anim)
}
}
-/* decode one video frame also considering the packet read into next_packet */
+/* decode one video frame also considering the packet read into cur_packet */
static int ffmpeg_decode_video_frame(struct anim *anim)
{
@@ -910,40 +902,43 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n");
- if (anim->next_packet->stream_index == anim->videoStream) {
- av_packet_unref(anim->next_packet);
- anim->next_packet->stream_index = -1;
+ if (anim->cur_packet->stream_index == anim->videoStream) {
+ av_packet_unref(anim->cur_packet);
+ anim->cur_packet->stream_index = -1;
}
- while ((rval = av_read_frame(anim->pFormatCtx, anim->next_packet)) >= 0) {
+ while ((rval = av_read_frame(anim->pFormatCtx, anim->cur_packet)) >= 0) {
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
"%sREAD: strID=%d (VID: %d) dts=%" PRId64 " pts=%" PRId64 " %s\n",
- (anim->next_packet->stream_index == anim->videoStream) ? "->" : " ",
- anim->next_packet->stream_index,
+ (anim->cur_packet->stream_index == anim->videoStream) ? "->" : " ",
+ anim->cur_packet->stream_index,
anim->videoStream,
- (anim->next_packet->dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet->dts,
- (anim->next_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet->pts,
- (anim->next_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : "");
- if (anim->next_packet->stream_index == anim->videoStream) {
+ (anim->cur_packet->dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->dts,
+ (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts,
+ (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : "");
+ if (anim->cur_packet->stream_index == anim->videoStream) {
anim->pFrameComplete = 0;
- avcodec_send_packet(anim->pCodecCtx, anim->next_packet);
+ avcodec_send_packet(anim->pCodecCtx, anim->cur_packet);
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->next_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame);
+ anim->cur_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame);
+ if (anim->pFrame->key_frame) {
+ anim->cur_key_frame_pts = anim->cur_pts;
+ }
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
- " FRAME DONE: next_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
+ " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
(anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
- (int64_t)anim->next_pts);
+ (int64_t)anim->cur_pts);
break;
}
}
- av_packet_unref(anim->next_packet);
- anim->next_packet->stream_index = -1;
+ av_packet_unref(anim->cur_packet);
+ anim->cur_packet->stream_index = -1;
}
if (rval == AVERROR_EOF) {
@@ -954,20 +949,23 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
if (anim->pFrameComplete) {
- anim->next_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame);
+ anim->cur_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame);
+ if (anim->pFrame->key_frame) {
+ anim->cur_key_frame_pts = anim->cur_pts;
+ }
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
- " FRAME DONE (after EOF): next_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
+ " FRAME DONE (after EOF): cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
(anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts,
- (int64_t)anim->next_pts);
+ (int64_t)anim->cur_pts);
rval = 0;
}
}
if (rval < 0) {
- av_packet_unref(anim->next_packet);
- anim->next_packet->stream_index = -1;
+ av_packet_unref(anim->cur_packet);
+ anim->cur_packet->stream_index = -1;
av_log(anim->pFormatCtx,
AV_LOG_ERROR,
@@ -1021,6 +1019,35 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
return false;
}
+static int64_t ffmpeg_get_seek_pos(struct anim *anim, int position)
+{
+ AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
+ double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
+ int64_t st_time = anim->pFormatCtx->start_time;
+ int64_t pos = (int64_t)(position)*AV_TIME_BASE;
+ /* Step back half a time base position to make sure that we get the requested
+ * frame and not the one after it.
+ */
+ pos -= (AV_TIME_BASE / 2);
+ pos /= frame_rate;
+
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n",
+ pos,
+ (st_time != AV_NOPTS_VALUE) ? st_time : 0);
+
+ if (pos < 0) {
+ pos = 0;
+ }
+
+ if (st_time != AV_NOPTS_VALUE) {
+ pos += st_time;
+ }
+
+ return pos;
+}
+
static int64_t ffmpeg_get_pts_to_search(struct anim *anim,
struct anim_index *tc_index,
int position)
@@ -1045,77 +1072,60 @@ static int64_t ffmpeg_get_pts_to_search(struct anim *anim,
return pts_to_search;
}
+/* Check if the pts will get us the same frame that we already have in memory from last decode. */
static bool ffmpeg_pts_matches_last_frame(struct anim *anim, int64_t pts_to_search)
{
- return anim->last_frame && anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search;
-}
-
-/* Requested video frame is expected to be found within different GOP as last decoded frame.
- * Seeking to new position and scanning is fastest way to get requested frame.
- * Check whether ffmpeg_can_scan() and ffmpeg_pts_matches_last_frame() is false before using this
- * function. */
-static bool ffmpeg_can_seek(struct anim *anim, int position)
-{
- return position != anim->curposition + 1;
-}
-
-/* Requested video frame is expected to be found within same GOP as last decoded frame.
- * Decoding frames in sequence until frame matches requested one is fastest way to get it. */
-static bool ffmpeg_can_scan(struct anim *anim, int position, struct anim_index *tc_index)
-{
- if (position > anim->curposition + 1 && anim->preseek && !tc_index &&
- position - (anim->curposition + 1) < anim->preseek) {
- return true;
- }
-
- if (tc_index == NULL) {
- return false;
+ if (anim->pFrame && anim->cur_frame_final) {
+ return labs(anim->cur_pts - pts_to_search) < anim->pFrame->pkt_duration;
}
- int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
- int old_frame_index = IMB_indexer_get_frame_index(tc_index, anim->curposition);
- return IMB_indexer_can_scan(tc_index, old_frame_index, new_frame_index);
+ return false;
}
static bool ffmpeg_is_first_frame_decode(struct anim *anim, int position)
{
- return position == 0 && anim->curposition == -1;
+ return position == 0 && anim->cur_position == -1;
}
/* Decode frames one by one until its PTS matches pts_to_search. */
static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_search)
{
- av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within preseek interval\n");
-
- /* there seem to exist *very* silly GOP lengths out in the wild... */
- int count = 1000;
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within current GOP\n");
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
"SCAN start: considering pts=%" PRId64 " in search of %" PRId64 "\n",
- (int64_t)anim->next_pts,
+ (int64_t)anim->cur_pts,
(int64_t)pts_to_search);
- while (count > 0 && anim->next_pts < pts_to_search) {
+ int64_t start_gop_frame = anim->cur_key_frame_pts;
+
+ while (anim->cur_pts < pts_to_search) {
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
" WHILE: pts=%" PRId64 " in search of %" PRId64 "\n",
- (int64_t)anim->next_pts,
+ (int64_t)anim->cur_pts,
(int64_t)pts_to_search);
if (!ffmpeg_decode_video_frame(anim)) {
break;
}
- count--;
+
+ if (start_gop_frame != anim->cur_key_frame_pts) {
+ break;
+ }
}
- if (count == 0) {
+
+ if (start_gop_frame != anim->cur_key_frame_pts) {
+ /* We went into an other GOP frame. This should never happen as we should have positioned us
+ * correctly by seeking into the GOP frame that contains the frame we want. */
av_log(anim->pFormatCtx,
AV_LOG_ERROR,
"SCAN failed: completely lost in stream, "
"bailing out at PTS=%" PRId64 ", searching for PTS=%" PRId64 "\n",
- (int64_t)anim->next_pts,
+ (int64_t)anim->cur_pts,
(int64_t)pts_to_search);
}
- if (anim->next_pts == pts_to_search) {
+ if (anim->cur_pts == pts_to_search) {
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
}
else {
@@ -1123,22 +1133,23 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea
}
}
-/* Wrapper over av_seek_frame(), for formats that doesn't have its own read_seek() or read_seek2()
- * functions defined. When seeking in these formats, rule to seek to last necessary I-frame is not
- * honored. It is not even guaranteed that I-frame, that must be decoded will be read. See
- * https://trac.ffmpeg.org/ticket/1607 and https://developer.blender.org/T86944. */
-static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t requested_pos)
+/* Wrapper over av_seek_frame(), for formats that doesn't have its own read_seek() or
+ * read_seek2() functions defined. When seeking in these formats, rule to seek to last
+ * necessary I-frame is not honored. It is not even guaranteed that I-frame, that must be
+ * decoded will be read. See https://trac.ffmpeg.org/ticket/1607 and
+ * https://developer.blender.org/T86944. */
+static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t *requested_pos)
{
AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
- int64_t current_pos = requested_pos;
+ int64_t current_pos = *requested_pos;
/* This time offset maximum limit is arbitrary. If some files fails to decode it may be
- * increased. Seek performance will be negatively affected. Small initial offset is necessary
- * because encoder can re-arrange frames as it needs but within it's delay, which is usually
- * small. */
+ * increased. Seek performance will be negatively affected. Small initial offset is
+ * necessary because encoder can re-arrange frames as it needs but within it's delay, which
+ * is usually small. */
for (int offset = 5; offset < 25; offset++) {
- current_pos = requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate);
+ current_pos = *requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate);
current_pos = max_ii(current_pos, 0);
/* Seek to timestamp. */
@@ -1147,42 +1158,51 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t requested_p
}
/* Read first video stream packet. */
- AVPacket read_packet = {0};
- while (av_read_frame(anim->pFormatCtx, &read_packet) >= 0) {
- if (anim->next_packet->stream_index == anim->videoStream) {
+ AVPacket *read_packet = av_packet_alloc();
+ while (av_read_frame(anim->pFormatCtx, read_packet) >= 0) {
+ if (anim->cur_packet->stream_index == anim->videoStream) {
break;
}
}
/* If this packet contains I-frame, exit loop. This should be the frame that we need. */
- if (read_packet.flags & AV_PKT_FLAG_KEY) {
+ bool is_key_frame = read_packet->flags & AV_PKT_FLAG_KEY;
+ av_packet_free(&read_packet);
+ if (is_key_frame) {
break;
}
}
+ *requested_pos = current_pos;
+
/* Re-seek to timestamp that gave I-frame, so it can be read by decode function. */
return av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD);
}
-/* Seek to last necessary I-frame and scan-decode until requested frame is found. */
-static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_index *tc_index)
+/* Seek to last necessary key frame. */
+static int ffmpeg_seek_to_key_frame(struct anim *anim, int position, struct anim_index *tc_index)
{
AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
- double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL));
- int64_t st_time = anim->pFormatCtx->start_time;
-
- int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
int64_t pos;
int ret;
if (tc_index) {
+ /* We can use timestamps generated from our indexer to seek. */
int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
+ int old_frame_index = IMB_indexer_get_frame_index(tc_index, anim->cur_position);
+
+ if (IMB_indexer_can_scan(tc_index, old_frame_index, new_frame_index)) {
+ /* No need to seek, return early. */
+ return 0;
+ }
uint64_t dts;
pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index);
dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index);
+ anim->cur_key_frame_pts = pos;
+
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pos = %" PRId64 "\n", pos);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts);
@@ -1198,22 +1218,9 @@ static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_
}
}
else {
- pos = (int64_t)(position)*AV_TIME_BASE / frame_rate;
-
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n",
- pos,
- (st_time != AV_NOPTS_VALUE) ? st_time : 0);
-
- if (pos < 0) {
- pos = 0;
- }
-
- if (st_time != AV_NOPTS_VALUE) {
- pos += st_time;
- }
-
+ /* We have to manually seek with ffmpeg to get to the key frame we want to start decoding from.
+ */
+ pos = ffmpeg_get_seek_pos(anim, position);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %" PRId64 "\n", pos);
AVFormatContext *format_ctx = anim->pFormatCtx;
@@ -1222,11 +1229,44 @@ static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_
ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
}
else {
- ret = ffmpeg_generic_seek_workaround(anim, pos);
+ ret = ffmpeg_generic_seek_workaround(anim, &pos);
+ av_log(anim->pFormatCtx, AV_LOG_DEBUG, "Adjusted final seek pos = %" PRId64 "\n", pos);
+ }
+
+ if (ret >= 0) {
+ /* Double check if we need to seek and decode all packets. */
+ AVPacket *current_gop_start_packet = av_packet_alloc();
+ while (av_read_frame(anim->pFormatCtx, current_gop_start_packet) >= 0) {
+ if (current_gop_start_packet->stream_index == anim->videoStream) {
+ break;
+ }
+ av_packet_unref(current_gop_start_packet);
+ }
+ bool same_gop = current_gop_start_packet->pts == anim->cur_key_frame_pts;
+
+ if (same_gop && position > anim->cur_position) {
+ /* Change back to our old frame position so we can simply continue decoding from there. */
+ AVPacket *temp = av_packet_alloc();
+ while (av_read_frame(anim->pFormatCtx, temp) >= 0) {
+ if (temp->stream_index == anim->videoStream && temp->pts == anim->cur_packet->pts) {
+ break;
+ }
+ av_packet_unref(temp);
+ }
+ av_packet_free(&current_gop_start_packet);
+ av_packet_free(&temp);
+ return 0;
+ }
+
+ anim->cur_key_frame_pts = current_gop_start_packet->pts;
+ av_packet_free(&current_gop_start_packet);
+ /* Seek back so we are at the correct position after we decoded a frame. */
+ av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
}
}
if (ret < 0) {
+ int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
av_log(anim->pFormatCtx,
AV_LOG_ERROR,
"FETCH: "
@@ -1234,25 +1274,19 @@ static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_
"): errcode = %d\n",
pos,
position,
- (int64_t)pts_to_search,
+ pts_to_search,
ret);
}
avcodec_flush_buffers(anim->pCodecCtx);
- anim->next_pts = -1;
+ anim->cur_pts = -1;
- if (anim->next_packet->stream_index == anim->videoStream) {
- av_packet_unref(anim->next_packet);
- anim->next_packet->stream_index = -1;
- }
-
- /* memset(anim->pFrame, ...) ?? */
- if (ret < 0) {
- /* Seek failed. */
- return;
+ if (anim->cur_packet->stream_index == anim->videoStream) {
+ av_packet_unref(anim->cur_packet);
+ anim->cur_packet->stream_index = -1;
}
- ffmpeg_decode_video_frame_scan(anim, pts_to_search);
+ return ret;
}
static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Type tc)
@@ -1282,25 +1316,22 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
if (ffmpeg_pts_matches_last_frame(anim, pts_to_search)) {
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
- "FETCH: frame repeat: last: %" PRId64 " next: %" PRId64 "\n",
- (int64_t)anim->last_pts,
- (int64_t)anim->next_pts);
- IMB_refImBuf(anim->last_frame);
- anim->curposition = position;
- return anim->last_frame;
+ "FETCH: frame repeat: pts: %" PRId64 "\n",
+ (int64_t)anim->cur_pts);
+ IMB_refImBuf(anim->cur_frame_final);
+ anim->cur_position = position;
+ return anim->cur_frame_final;
}
- if (ffmpeg_can_scan(anim, position, tc_index) || ffmpeg_is_first_frame_decode(anim, position)) {
- ffmpeg_decode_video_frame_scan(anim, pts_to_search);
- }
- else if (ffmpeg_can_seek(anim, position)) {
- ffmpeg_seek_and_decode(anim, position, tc_index);
- }
- else {
+ if (position == anim->cur_position + 1 || ffmpeg_is_first_frame_decode(anim, position)) {
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: no seek necessary, just continue...\n");
+ ffmpeg_decode_video_frame(anim);
+ }
+ else if (ffmpeg_seek_to_key_frame(anim, position, tc_index) >= 0) {
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
}
- IMB_freeImBuf(anim->last_frame);
+ IMB_freeImBuf(anim->cur_frame_final);
/* Certain versions of FFmpeg have a bug in libswscale which ends up in crash
* when destination buffer is not properly aligned. For example, this happens
@@ -1320,23 +1351,20 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
*
* The issue was reported to FFmpeg under ticket #8747 in the FFmpeg tracker
* and is fixed in the newer versions than 4.3.1. */
- anim->last_frame = IMB_allocImBuf(anim->x, anim->y, 32, 0);
- anim->last_frame->rect = MEM_mallocN_aligned((size_t)4 * anim->x * anim->y, 32, "ffmpeg ibuf");
- anim->last_frame->mall |= IB_rect;
+ anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, 32, 0);
+ anim->cur_frame_final->rect = MEM_mallocN_aligned(
+ (size_t)4 * anim->x * anim->y, 32, "ffmpeg ibuf");
+ anim->cur_frame_final->mall |= IB_rect;
- anim->last_frame->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);
+ anim->cur_frame_final->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);
ffmpeg_postprocess(anim);
- anim->last_pts = anim->next_pts;
-
- ffmpeg_decode_video_frame(anim);
+ anim->cur_position = position;
- anim->curposition = position;
+ IMB_refImBuf(anim->cur_frame_final);
- IMB_refImBuf(anim->last_frame);
-
- return anim->last_frame;
+ return anim->cur_frame_final;
}
static void free_anim_ffmpeg(struct anim *anim)
@@ -1348,7 +1376,7 @@ static void free_anim_ffmpeg(struct anim *anim)
if (anim->pCodecCtx) {
avcodec_free_context(&anim->pCodecCtx);
avformat_close_input(&anim->pFormatCtx);
- av_packet_free(&anim->next_packet);
+ av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrame);
@@ -1369,7 +1397,7 @@ static void free_anim_ffmpeg(struct anim *anim)
av_frame_free(&anim->pFrameDeinterlaced);
sws_freeContext(anim->img_convert_ctx);
- IMB_freeImBuf(anim->last_frame);
+ IMB_freeImBuf(anim->cur_frame_final);
}
anim->duration_in_frames = 0;
}
@@ -1503,13 +1531,13 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
an_stringenc(anim->name, head, tail, digits, pic);
ibuf = IMB_loadiffname(anim->name, IB_rect, anim->colorspace);
if (ibuf) {
- anim->curposition = position;
+ anim->cur_position = position;
}
break;
case ANIM_MOVIE:
ibuf = movie_fetchibuf(anim, position);
if (ibuf) {
- anim->curposition = position;
+ anim->cur_position = position;
IMB_convert_rgba_to_abgr(ibuf);
}
break;
@@ -1517,7 +1545,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
case ANIM_AVI:
ibuf = avi_fetchibuf(anim, position);
if (ibuf) {
- anim->curposition = position;
+ anim->cur_position = position;
}
break;
#endif
@@ -1525,7 +1553,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
case ANIM_FFMPEG:
ibuf = ffmpeg_fetchibuf(anim, position, tc);
if (ibuf) {
- anim->curposition = position;
+ anim->cur_position = position;
}
filter_y = 0; /* done internally */
break;
@@ -1536,7 +1564,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
if (filter_y) {
IMB_filtery(ibuf);
}
- BLI_snprintf(ibuf->name, sizeof(ibuf->name), "%s.%04d", anim->name, anim->curposition + 1);
+ BLI_snprintf(ibuf->name, sizeof(ibuf->name), "%s.%04d", anim->name, anim->cur_position + 1);
}
return ibuf;
}
@@ -1591,16 +1619,6 @@ bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bo
return false;
}
-void IMB_anim_set_preseek(struct anim *anim, int preseek)
-{
- anim->preseek = preseek;
-}
-
-int IMB_anim_get_preseek(struct anim *anim)
-{
- return anim->preseek;
-}
-
int IMB_anim_get_image_width(struct anim *anim)
{
return anim->x;