static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Type tc) { int64_t pts_to_search = 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 = 0; /* To quiet gcc barking... */ int old_frame_index = 0; /* To quiet gcc barking... */ if (anim == 0) return (0); av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position); 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; } } av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: looking for PTS=%lld " "(pts_timebase=%g, frame_rate=%g, st_time=%lld)\n", (long long int)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", (long long int)anim->last_pts, (long long int)anim->next_pts); IMB_refImBuf(anim->last_frame); anim->curposition = position; return anim->last_frame; } 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"); ffmpeg_decode_video_frame_scan(anim, pts_to_search); } else if (position != anim->curposition + 1) { long long pos; int ret; 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); 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; av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX seek pos = %lld, st_time = %lld\n", pos, (st_time != AV_NOPTS_VALUE) ? st_time : 0); if (pos < 0) { pos = 0; } if (st_time != AV_NOPTS_VALUE) { pos += st_time; } av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %lld\n", pos); ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); } 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, (long long int)pts_to_search, ret); } avcodec_flush_buffers(anim->pCodecCtx); anim->next_pts = -1; if (anim->next_packet.stream_index == anim->videoStream) { av_free_packet(&anim->next_packet); anim->next_packet.stream_index = -1; } /* memset(anim->pFrame, ...) ?? */ if (ret >= 0) { ffmpeg_decode_video_frame_scan(anim, pts_to_search); } } else if (position == 0 && anim->curposition == -1) { /* first frame without seeking special case... */ ffmpeg_decode_video_frame(anim); } else { av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: no seek necessary, just continue...\n"); } IMB_freeImBuf(anim->last_frame); anim->last_frame = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect); anim->last_frame->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace); ffmpeg_postprocess(anim); anim->last_pts = anim->next_pts; ffmpeg_decode_video_frame(anim); anim->curposition = position; IMB_refImBuf(anim->last_frame); return anim->last_frame; }
static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { ImBuf * ibuf; int frameFinished; AVPacket packet; int64_t pts_to_search = 0; int pos_found = 1; int filter_y = 0; int seek_by_bytes= 0; int preseek_count = 0; if (anim == 0) return (0); ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect); 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; } } } } /* 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 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); 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; pos *= anim->pFormatCtx->bit_rate / frame_rate; pos /= 8; } 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); } 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; } 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); if (seek_by_bytes && preseek_count > 0) { preseek_count--; } 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; } } } if(frameFinished && pos_found == 1) { ffmpeg_postprocess(anim, ibuf, &filter_y); av_free_packet(&packet); break; } } av_free_packet(&packet); } if (filter_y && ibuf) { IMB_filtery(ibuf); } ibuf->profile = IB_PROFILE_SRGB; return(ibuf); }