diff options
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r-- | source/blender/imbuf/IMB_imbuf.h | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/IMB_anim.h | 11 | ||||
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 360 |
3 files changed, 194 insertions, 179 deletions
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index d131e4dacdc..9c84127105a 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -380,8 +380,6 @@ bool IMB_anim_can_produce_frames(const struct anim *anim); */ int ismovie(const char *filepath); -void IMB_anim_set_preseek(struct anim *anim, int preseek); -int IMB_anim_get_preseek(struct anim *anim); int IMB_anim_get_image_width(struct anim *anim); int IMB_anim_get_image_height(struct anim *anim); diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 7d7864306a1..cfeffcca0ea 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -87,7 +87,7 @@ struct anim_index; struct anim { int ib_flags; int curtype; - int curposition; /* index 0 = 1e, 1 = 2e, enz. */ + int cur_position; /* index 0 = 1e, 1 = 2e, enz. */ int duration_in_frames; int frs_sec; double frs_sec_base; @@ -105,7 +105,6 @@ struct anim { int orientation; size_t framesize; int interlacing; - int preseek; int streamindex; /* avi */ @@ -132,10 +131,10 @@ struct anim { struct SwsContext *img_convert_ctx; int videoStream; - struct ImBuf *last_frame; - int64_t last_pts; - int64_t next_pts; - AVPacket *next_packet; + struct ImBuf *cur_frame_final; + int64_t cur_pts; + int64_t cur_key_frame_pts; + AVPacket *cur_packet; #endif char index_dir[768]; diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 5058bd2f637..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,13 +705,6 @@ 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, @@ -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(¤t_gop_start_packet); + av_packet_free(&temp); + return 0; + } + + anim->cur_key_frame_pts = current_gop_start_packet->pts; + av_packet_free(¤t_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; |