45# include <libavcodec/avcodec.h>
46# include <libavformat/avformat.h>
47# include <libavutil/imgutils.h>
48# include <libavutil/rational.h>
49# include <libswscale/swscale.h>
57static void free_anim_ffmpeg(
ImBufAnim *anim);
62 if (anim ==
nullptr) {
63 printf(
"free anim, anim == nullptr\n");
68 free_anim_ffmpeg(anim);
78 if (anim ==
nullptr) {
87 if (anim ==
nullptr) {
99 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"METADATA FETCH\n");
101 AVDictionaryEntry *entry =
nullptr;
103 entry = av_dict_get(anim->pFormatCtx->
metadata,
"", entry, AV_DICT_IGNORE_SUFFIX);
104 if (entry ==
nullptr) {
127 if (anim !=
nullptr) {
146#if !defined(WITH_FFMPEG)
151 if (anim->pCodecCtx !=
nullptr) {
165static double ffmpeg_stream_start_time_get(AVStream *stream)
167 if (stream->start_time == AV_NOPTS_VALUE) {
171 return stream->start_time * av_q2d(stream->time_base);
174static int ffmpeg_container_frame_count_get(AVFormatContext *pFormatCtx, AVStream *video_stream)
181 const double video_start = ffmpeg_stream_start_time_get(video_stream);
182 double audio_start = 0;
184 for (
int i = 0; i < pFormatCtx->nb_streams; i++) {
185 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
186 AVStream *audio_stream = pFormatCtx->streams[i];
187 audio_start = ffmpeg_stream_start_time_get(audio_stream);
192 const AVRational frame_rate = av_guess_frame_rate(pFormatCtx, video_stream,
nullptr);
195 if (video_start > audio_start) {
196 stream_dur =
double(pFormatCtx->duration) / AV_TIME_BASE - (video_start - audio_start);
202 stream_dur =
double(pFormatCtx->duration) / AV_TIME_BASE;
205 return lround(stream_dur * av_q2d(frame_rate));
208static int ffmpeg_frame_count_get(AVFormatContext *pFormatCtx, AVStream *video_stream)
211 if (video_stream->duration != AV_NOPTS_VALUE) {
212 const AVRational frame_rate = av_guess_frame_rate(pFormatCtx, video_stream,
nullptr);
213 const double stream_dur = video_stream->duration * av_q2d(video_stream->time_base);
214 return lround(stream_dur * av_q2d(frame_rate));
220 if (pFormatCtx->duration != AV_NOPTS_VALUE) {
221 return ffmpeg_container_frame_count_get(pFormatCtx, video_stream);
225 if (video_stream->nb_frames != 0) {
226 return video_stream->nb_frames;
233 BLI_assert(pFormatCtx->duration == AV_NOPTS_VALUE);
239 const AVCodec *pCodec;
240 AVFormatContext *pFormatCtx =
nullptr;
241 AVCodecContext *pCodecCtx;
242 AVStream *video_stream;
243 int video_stream_index;
249 int srcRange, dstRange, brightness, contrast,
saturation;
251 const int *inv_table;
253 if (anim ==
nullptr) {
259 if (avformat_open_input(&pFormatCtx, anim->
filepath,
nullptr,
nullptr) != 0) {
263 if (avformat_find_stream_info(pFormatCtx,
nullptr) < 0) {
264 avformat_close_input(&pFormatCtx);
268 av_dump_format(pFormatCtx, 0, anim->
filepath, 0);
271 video_stream_index = -1;
273 for (
int i = 0; i < pFormatCtx->nb_streams; i++) {
274 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
275 if (streamcount > 0) {
279 video_stream_index = i;
284 if (video_stream_index == -1) {
285 avformat_close_input(&pFormatCtx);
289 video_stream = pFormatCtx->streams[video_stream_index];
292 pCodec = avcodec_find_decoder(video_stream->codecpar->codec_id);
293 if (pCodec ==
nullptr) {
294 avformat_close_input(&pFormatCtx);
298 pCodecCtx = avcodec_alloc_context3(
nullptr);
299 avcodec_parameters_to_context(pCodecCtx, video_stream->codecpar);
300 pCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
302 if (pCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
303 pCodecCtx->thread_count = 0;
309 if (pCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
310 pCodecCtx->thread_type = FF_THREAD_FRAME;
312 else if (pCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
313 pCodecCtx->thread_type = FF_THREAD_SLICE;
316 if (avcodec_open2(pCodecCtx, pCodec,
nullptr) < 0) {
317 avformat_close_input(&pFormatCtx);
320 if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) {
321 avcodec_free_context(&anim->pCodecCtx);
322 avformat_close_input(&pFormatCtx);
326 const AVRational frame_rate = av_guess_frame_rate(pFormatCtx, video_stream,
nullptr);
327 frs_num = frame_rate.num;
328 frs_den = frame_rate.den;
330 frs_den *= AV_TIME_BASE;
332 while (frs_num % 10 == 0 && frs_den >= 2.0 && frs_num > 10) {
341 anim->
start_offset = ffmpeg_stream_start_time_get(video_stream);
344 anim->
x = pCodecCtx->width;
345 anim->
y = pCodecCtx->height;
347 anim->pFormatCtx = pFormatCtx;
348 anim->pCodecCtx = pCodecCtx;
349 anim->pCodec = pCodec;
350 anim->videoStream = video_stream_index;
354 anim->cur_key_frame_pts = -1;
355 anim->cur_packet = av_packet_alloc();
356 anim->cur_packet->stream_index = -1;
358 anim->pFrame = av_frame_alloc();
359 anim->pFrame_backup = av_frame_alloc();
360 anim->pFrame_backup_complete =
false;
361 anim->pFrame_complete =
false;
362 anim->pFrameDeinterlaced = av_frame_alloc();
363 anim->pFrameRGB = av_frame_alloc();
364 anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
365 anim->pFrameRGB->width = anim->
x;
366 anim->pFrameRGB->height = anim->
y;
369 if (av_frame_get_buffer(anim->pFrameRGB, align) < 0) {
370 fprintf(stderr,
"Could not allocate frame data.\n");
371 avcodec_free_context(&anim->pCodecCtx);
372 avformat_close_input(&anim->pFormatCtx);
373 av_packet_free(&anim->cur_packet);
374 av_frame_free(&anim->pFrameRGB);
375 av_frame_free(&anim->pFrameDeinterlaced);
376 av_frame_free(&anim->pFrame);
377 av_frame_free(&anim->pFrame_backup);
378 anim->pCodecCtx =
nullptr;
382 if (av_image_get_buffer_size(AV_PIX_FMT_RGBA, anim->
x, anim->
y, 1) != anim->
x * anim->
y * 4) {
383 fprintf(stderr,
"ffmpeg has changed alloc scheme ... ARGHHH!\n");
384 avcodec_free_context(&anim->pCodecCtx);
385 avformat_close_input(&anim->pFormatCtx);
386 av_packet_free(&anim->cur_packet);
387 av_frame_free(&anim->pFrameRGB);
388 av_frame_free(&anim->pFrameDeinterlaced);
389 av_frame_free(&anim->pFrame);
390 av_frame_free(&anim->pFrame_backup);
391 anim->pCodecCtx =
nullptr;
396 anim->pFrameDeinterlaced->format = anim->pCodecCtx->pix_fmt;
397 anim->pFrameDeinterlaced->width = anim->pCodecCtx->width;
398 anim->pFrameDeinterlaced->height = anim->pCodecCtx->height;
399 av_image_fill_arrays(
400 anim->pFrameDeinterlaced->data,
401 anim->pFrameDeinterlaced->linesize,
403 av_image_get_buffer_size(
404 anim->pCodecCtx->pix_fmt, anim->pCodecCtx->width, anim->pCodecCtx->height, 1),
405 "ffmpeg deinterlace")),
406 anim->pCodecCtx->pix_fmt,
407 anim->pCodecCtx->width,
408 anim->pCodecCtx->height,
412 anim->img_convert_ctx = BKE_ffmpeg_sws_get_context(anim->
x,
414 anim->pCodecCtx->pix_fmt,
418 SWS_BILINEAR | SWS_PRINT_INFO |
421 if (!anim->img_convert_ctx) {
422 fprintf(stderr,
"Can't transform color space??? Bailing out...\n");
423 avcodec_free_context(&anim->pCodecCtx);
424 avformat_close_input(&anim->pFormatCtx);
425 av_packet_free(&anim->cur_packet);
426 av_frame_free(&anim->pFrameRGB);
427 av_frame_free(&anim->pFrameDeinterlaced);
428 av_frame_free(&anim->pFrame);
429 av_frame_free(&anim->pFrame_backup);
430 anim->pCodecCtx =
nullptr;
435 if (!sws_getColorspaceDetails(anim->img_convert_ctx,
444 srcRange = srcRange || anim->pCodecCtx->color_range == AVCOL_RANGE_JPEG;
445 inv_table = sws_getCoefficients(anim->pCodecCtx->
colorspace);
447 if (sws_setColorspaceDetails(anim->img_convert_ctx,
456 fprintf(stderr,
"Warning: Could not set libswscale colorspace details.\n");
460 fprintf(stderr,
"Warning: Could not set libswscale colorspace details.\n");
466static double ffmpeg_steps_per_frame_get(
ImBufAnim *anim)
468 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
469 AVRational time_base = v_st->time_base;
470 AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st,
nullptr);
471 return av_q2d(av_inv_q(av_mul_q(frame_rate, time_base)));
479static void ffmpeg_double_buffer_backup_frame_store(
ImBufAnim *anim,
int64_t pts_to_search)
482 if (anim->pFrame_backup_complete && anim->cur_pts >= pts_to_search) {
485 if (!anim->pFrame_complete) {
489 if (anim->pFrame_backup_complete) {
490 av_frame_unref(anim->pFrame_backup);
493 av_frame_move_ref(anim->pFrame_backup, anim->pFrame);
494 anim->pFrame_backup_complete =
true;
498static void ffmpeg_double_buffer_backup_frame_clear(
ImBufAnim *anim)
500 if (anim->pFrame_backup_complete) {
501 av_frame_unref(anim->pFrame_backup);
503 anim->pFrame_backup_complete =
false;
507static AVFrame *ffmpeg_double_buffer_frame_fallback_get(
ImBufAnim *anim)
509 av_log(anim->pFormatCtx, AV_LOG_ERROR,
"DECODE UNHAPPY: PTS not matched!\n");
511 if (anim->pFrame_complete) {
514 if (anim->pFrame_backup_complete) {
515 return anim->pFrame_backup;
525static void ffmpeg_postprocess(
ImBufAnim *anim, AVFrame *input,
ImBuf *ibuf)
531 if (input->data[0] ==
nullptr && input->data[1] ==
nullptr && input->data[2] ==
nullptr &&
532 input->data[3] ==
nullptr)
536 "data not read properly...\n");
540 av_log(anim->pFormatCtx,
542 " POSTPROC: AVFrame planes: %p %p %p %p\n",
551 anim->pCodecCtx->pix_fmt,
552 anim->pCodecCtx->width,
553 anim->pCodecCtx->height) < 0)
558 input = anim->pFrameDeinterlaced;
566 const int ibuf_linesize = ibuf->
x * 4;
567 const int rgb_linesize = anim->pFrameRGB->linesize[0];
568 bool scale_to_ibuf = (rgb_linesize == ibuf_linesize);
572# if (defined(__aarch64__) || defined(_M_ARM64)) && (LIBSWSCALE_VERSION_MAJOR < 7)
573 scale_to_ibuf =
false;
575 uint8_t *rgb_data = anim->pFrameRGB->data[0];
580 anim->pFrameRGB->linesize[0] = -ibuf_linesize;
581 anim->pFrameRGB->data[0] = ibuf->
byte_buffer.
data + (ibuf->
y - 1) * ibuf_linesize;
583 BKE_ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB, input);
585 anim->pFrameRGB->linesize[0] = rgb_linesize;
586 anim->pFrameRGB->data[0] = rgb_data;
590 BKE_ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB, input);
593 const int src_linesize[4] = {-rgb_linesize, 0, 0, 0};
594 const uint8_t *
const src[4] = {
595 rgb_data + (anim->
y - 1) * rgb_linesize,
nullptr,
nullptr,
nullptr};
596 int dst_size = av_image_get_buffer_size(AVPixelFormat(anim->pFrameRGB->format),
597 anim->pFrameRGB->width,
598 anim->pFrameRGB->height,
600 av_image_copy_to_buffer(
601 ibuf->
byte_buffer.
data, dst_size, src, src_linesize, AV_PIX_FMT_RGBA, anim->
x, anim->
y, 1);
609static void final_frame_log(
ImBufAnim *anim,
614 av_log(anim->pFormatCtx,
616 "DECODE HAPPY: %s frame PTS range %" PRId64 " - %" PRId64 ".\n",
624 return pts_start <= pts_to_search && pts_to_search < pts_end;
628static AVFrame *ffmpeg_frame_by_pts_get(
ImBufAnim *anim,
int64_t pts_to_search)
634 if (!anim->pFrame_complete) {
638 const bool backup_frame_ready = anim->pFrame_backup_complete;
643 AVFrame *best_frame =
nullptr;
644 if (ffmpeg_pts_isect(recent_start, recent_end, pts_to_search)) {
645 final_frame_log(anim, recent_start, recent_end,
"Recent");
646 best_frame = anim->pFrame;
648 else if (backup_frame_ready && ffmpeg_pts_isect(backup_start, recent_start, pts_to_search)) {
649 final_frame_log(anim, backup_start, recent_start,
"Backup");
650 best_frame = anim->pFrame_backup;
655static void ffmpeg_decode_store_frame_pts(
ImBufAnim *anim)
659# ifdef FFMPEG_OLD_KEY_FRAME_QUERY_METHOD
660 if (anim->pFrame->key_frame) {
662 if (anim->pFrame->flags & AV_FRAME_FLAG_KEY) {
664 anim->cur_key_frame_pts = anim->cur_pts;
667 av_log(anim->pFormatCtx,
669 " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
674static int ffmpeg_read_video_frame(
ImBufAnim *anim, AVPacket *packet)
677 while ((
ret = av_read_frame(anim->pFormatCtx, packet)) >= 0) {
678 if (packet->stream_index == anim->videoStream) {
681 av_packet_unref(packet);
682 packet->stream_index = -1;
689static int ffmpeg_decode_video_frame(
ImBufAnim *anim)
691 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
" DECODE VIDEO FRAME\n");
695 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
696 if (anim->pFrame_complete) {
697 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
" DECODE FROM CODEC BUFFER\n");
698 ffmpeg_decode_store_frame_pts(anim);
703 if (anim->cur_packet->stream_index == anim->videoStream) {
704 av_packet_unref(anim->cur_packet);
705 anim->cur_packet->stream_index = -1;
708 while ((rval = ffmpeg_read_video_frame(anim, anim->cur_packet)) >= 0) {
709 if (anim->cur_packet->stream_index != anim->videoStream) {
713 av_log(anim->pFormatCtx,
716 anim->cur_packet->stream_index,
717 (anim->cur_packet->dts == AV_NOPTS_VALUE) ? -1 :
int64_t(anim->cur_packet->dts),
718 (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 :
int64_t(anim->cur_packet->pts),
719 (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ?
" KEY" :
"");
721 avcodec_send_packet(anim->pCodecCtx, anim->cur_packet);
722 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
724 if (anim->pFrame_complete) {
725 ffmpeg_decode_store_frame_pts(anim);
728 av_packet_unref(anim->cur_packet);
729 anim->cur_packet->stream_index = -1;
732 if (rval == AVERROR_EOF) {
734 avcodec_send_packet(anim->pCodecCtx,
nullptr);
735 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
737 if (anim->pFrame_complete) {
738 ffmpeg_decode_store_frame_pts(anim);
744 av_packet_unref(anim->cur_packet);
745 anim->cur_packet->stream_index = -1;
747 char error_str[AV_ERROR_MAX_STRING_SIZE];
748 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, rval);
750 av_log(anim->pFormatCtx,
752 " DECODE READ FAILED: av_read_frame() "
753 "returned error: %s\n",
760static int match_format(
const char *name, AVFormatContext *pFormatCtx)
765 const char *names = pFormatCtx->iformat->name;
767 if (!name || !names) {
771 namelen = strlen(name);
772 while ((p = strchr(names,
','))) {
773 len = std::max(
int(p - names), namelen);
782static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
784 static const char *byte_seek_list[] = {
"mpegts",
nullptr};
787 if (pFormatCtx->iformat->flags & AVFMT_TS_DISCONT) {
794 if (match_format(*p++, pFormatCtx)) {
811 int64_t seek_pts = pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3);
831 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
832 int64_t start_pts = v_st->start_time;
834 pts_to_search =
round(position * ffmpeg_steps_per_frame_get(anim));
836 if (start_pts != AV_NOPTS_VALUE) {
837 pts_to_search += start_pts;
840 return pts_to_search;
843static bool ffmpeg_is_first_frame_decode(
ImBufAnim *anim)
845 return anim->pFrame_complete ==
false;
852 av_log(anim->pFormatCtx,
861static void ffmpeg_decode_video_frame_scan(
ImBufAnim *anim,
int64_t pts_to_search)
863 const int64_t start_gop_frame = anim->cur_key_frame_pts;
864 bool decode_error =
false;
866 while (!decode_error && anim->cur_pts < pts_to_search) {
867 ffmpeg_scan_log(anim, pts_to_search);
868 ffmpeg_double_buffer_backup_frame_store(anim, pts_to_search);
869 decode_error = ffmpeg_decode_video_frame(anim) < 1;
875 if (anim->seek_before_decode && start_gop_frame != anim->cur_key_frame_pts) {
876 av_log(anim->pFormatCtx, AV_LOG_ERROR,
"SCAN: Frame belongs to an unexpected GOP!\n");
885static int ffmpeg_generic_seek_workaround(
ImBufAnim *anim,
889 int64_t current_pts = *requested_pts;
892 int64_t cur_pts, prev_pts = -1;
895 while (current_pts != 0) {
896 current_pts = *requested_pts -
int64_t(
round(offset * ffmpeg_steps_per_frame_get(anim)));
897 current_pts = std::max(current_pts,
int64_t(0));
900 if (av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD) < 0)
906 AVPacket *read_packet = av_packet_alloc();
907 while (av_read_frame(anim->pFormatCtx, read_packet) >= 0) {
908 if (read_packet->stream_index == anim->videoStream) {
911 av_packet_unref(read_packet);
915 bool is_key_frame = read_packet->flags & AV_PKT_FLAG_KEY;
920 av_packet_free(&read_packet);
923 if (cur_pts <= pts_to_search) {
929 if (cur_pts == prev_pts) {
939 *requested_pts = current_pts;
942 return av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD);
947static void ffmpeg_seek_recover_stream_position(
ImBufAnim *anim)
949 AVPacket *temp_packet = av_packet_alloc();
950 while (ffmpeg_read_video_frame(anim, temp_packet) >= 0) {
953 av_packet_unref(temp_packet);
955 if (current_pts == temp_pts) {
959 av_packet_free(&temp_packet);
963static bool ffmpeg_seek_buffers_need_flushing(
ImBufAnim *anim,
int position,
int64_t seek_pos)
966 AVPacket *temp_packet = av_packet_alloc();
967 ffmpeg_read_video_frame(anim, temp_packet);
969 av_packet_unref(temp_packet);
970 av_packet_free(&temp_packet);
980 if (gop_pts == anim->cur_key_frame_pts && position > anim->
cur_position) {
981 ffmpeg_seek_recover_stream_position(anim);
986 av_seek_frame(anim->pFormatCtx, anim->videoStream, seek_pos, AVSEEK_FLAG_BACKWARD);
987 anim->cur_key_frame_pts = gop_pts;
992static int ffmpeg_seek_to_key_frame(
ImBufAnim *anim,
1018 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"TC INDEX seek seek_pos = %" PRId64 "\n", seek_pos);
1019 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"TC INDEX seek pts = %" PRIu64 "\n", pts);
1020 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"TC INDEX seek dts = %" PRIu64 "\n", dts);
1022 if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
1023 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"... using BYTE seek_pos\n");
1025 ret = av_seek_frame(anim->pFormatCtx, -1, seek_pos, AVSEEK_FLAG_BYTE);
1028 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"... using PTS seek_pos\n");
1029 ret = av_seek_frame(
1030 anim->pFormatCtx, anim->videoStream, anim->cur_key_frame_pts, AVSEEK_FLAG_BACKWARD);
1036 seek_pos = ffmpeg_get_seek_pts(anim, pts_to_search);
1038 anim->pFormatCtx, AV_LOG_DEBUG,
"NO INDEX final seek seek_pos = %" PRId64 "\n", seek_pos);
1040 AVFormatContext *format_ctx = anim->pFormatCtx;
1046 if (!(format_ctx->iformat->flags & AVFMT_TS_DISCONT)) {
1047 ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, seek_pos, AVSEEK_FLAG_BACKWARD);
1050 ret = ffmpeg_generic_seek_workaround(anim, &seek_pos, pts_to_search);
1051 av_log(anim->pFormatCtx,
1053 "Adjusted final seek seek_pos = %" PRId64 "\n",
1057 if (
ret <= 0 && !ffmpeg_seek_buffers_need_flushing(anim, position, seek_pos)) {
1063 av_log(anim->pFormatCtx,
1066 "error while seeking to DTS = %" PRId64 " (frameno = %d, PTS = %" PRId64
1067 "): errcode = %d\n",
1075 avcodec_flush_buffers(anim->pCodecCtx);
1076 ffmpeg_double_buffer_backup_frame_clear(anim);
1080 if (anim->cur_packet->stream_index == anim->videoStream) {
1081 av_packet_unref(anim->cur_packet);
1082 anim->cur_packet->stream_index = -1;
1088static bool ffmpeg_must_decode(
ImBufAnim *anim,
int position)
1090 return !anim->pFrame_complete || anim->
cur_position != position;
1093static bool ffmpeg_must_seek(
ImBufAnim *anim,
int position)
1095 bool must_seek = position != anim->
cur_position + 1 || ffmpeg_is_first_frame_decode(anim);
1096 anim->seek_before_decode = must_seek;
1102 if (anim ==
nullptr) {
1106 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"FETCH: seek_pos=%d\n", position);
1109 int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
1110 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
1111 double frame_rate = av_q2d(v_st->r_frame_rate);
1112 double pts_time_base = av_q2d(v_st->time_base);
1113 int64_t start_pts = v_st->start_time;
1115 av_log(anim->pFormatCtx,
1117 "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, start_pts=%" PRId64
1124 if (ffmpeg_must_decode(anim, position)) {
1125 if (ffmpeg_must_seek(anim, position)) {
1126 ffmpeg_seek_to_key_frame(anim, position, tc_index, pts_to_search);
1129 ffmpeg_decode_video_frame_scan(anim, pts_to_search);
1133 anim->
x = anim->pCodecCtx->width;
1134 anim->
y = anim->pCodecCtx->height;
1136 const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt);
1139 if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) {
1153 AVFrame *final_frame = ffmpeg_frame_by_pts_get(anim, pts_to_search);
1154 if (final_frame ==
nullptr) {
1157 final_frame = ffmpeg_double_buffer_frame_fallback_get(anim);
1162 if (final_frame !=
nullptr) {
1163 ffmpeg_postprocess(anim, final_frame, cur_frame_final);
1168 return cur_frame_final;
1171static void free_anim_ffmpeg(
ImBufAnim *anim)
1173 if (anim ==
nullptr) {
1177 if (anim->pCodecCtx) {
1178 avcodec_free_context(&anim->pCodecCtx);
1179 avformat_close_input(&anim->pFormatCtx);
1180 av_packet_free(&anim->cur_packet);
1182 av_frame_free(&anim->pFrame);
1183 av_frame_free(&anim->pFrame_backup);
1184 av_frame_free(&anim->pFrameRGB);
1185 if (anim->pFrameDeinterlaced->data[0] !=
nullptr) {
1186 MEM_freeN(anim->pFrameDeinterlaced->data[0]);
1188 av_frame_free(&anim->pFrameDeinterlaced);
1189 BKE_ffmpeg_sws_release_context(anim->img_convert_ctx);
1202 if (anim ==
nullptr) {
1210 free_anim_ffmpeg(anim);
1211 if (startffmpeg(anim)) {
1222 ImBuf *ibuf =
nullptr;
1241 if (anim->pFormatCtx) {
1242 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
1243 AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st,
nullptr);
1244 if (frame_rate.num != 0) {
1246 SNPRINTF(value,
"%g", av_q2d(frame_rate));
1263 ImBuf *ibuf =
nullptr;
1264 if (anim ==
nullptr) {
1294 ibuf = ffmpeg_fetchibuf(anim, position, tc);
1332 float *r_frs_sec_base)
1334 double frs_sec_base_double;
1336 if (anim->
frs_sec > SHRT_MAX) {
1339 *r_frs_sec = SHRT_MAX;
1348 *r_frs_sec_base =
float(frs_sec_base_double / AV_TIME_BASE);
1351 *r_frs_sec_base =
float(frs_sec_base_double);
1355 *r_frs_sec_base =
float(frs_sec_base_double);
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
int char char int int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define STRNCPY(dst, src)
#define SNPRINTF(dst, format,...)
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int BLI_system_thread_count(void)
typedef double(DMatrix)[4][4]
@ COLOR_ROLE_DEFAULT_BYTE
int IMB_anim_index_get_frame_index(ImBufAnim *anim, IMB_Timecode_Type tc, int position)
void IMB_filtery(ImBuf *ibuf)
void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, ImBufOwnership ownership)
Contains defines and structs used throughout the imbuf module.
uint64_t IMB_indexer_get_seek_pos(ImBufAnimIndex *idx, int frame_index)
int IMB_indexer_get_frame_index(ImBufAnimIndex *idx, int frameno)
int IMB_indexer_get_duration(ImBufAnimIndex *idx)
ImBufAnimIndex * IMB_anim_open_index(ImBufAnim *anim, IMB_Timecode_Type tc)
uint64_t IMB_indexer_get_seek_pos_pts(ImBufAnimIndex *idx, int frame_index)
ImBufAnim * IMB_anim_open_proxy(ImBufAnim *anim, IMB_Proxy_Size preview_size)
uint64_t IMB_indexer_get_seek_pos_dts(ImBufAnimIndex *idx, int frame_index)
uint64_t IMB_indexer_get_pts(ImBufAnimIndex *idx, int frame_index)
int IMB_indexer_can_scan(ImBufAnimIndex *idx, int old_frame_index, int new_frame_index)
void IMB_free_indices(ImBufAnim *anim)
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its saturation
bool IMB_anim_can_produce_frames(const ImBufAnim *anim)
int IMB_anim_get_image_height(ImBufAnim *anim)
ImBuf * IMB_anim_absolute(ImBufAnim *anim, int position, IMB_Timecode_Type tc, IMB_Proxy_Size preview_size)
double IMD_anim_get_offset(ImBufAnim *anim)
static bool anim_getnew(ImBufAnim *anim)
bool IMB_anim_get_fps(const ImBufAnim *anim, bool no_av_base, short *r_frs_sec, float *r_frs_sec_base)
int IMB_anim_get_image_width(ImBufAnim *anim)
ImBuf * IMB_anim_previewframe(ImBufAnim *anim)
void IMB_free_anim(ImBufAnim *anim)
IDProperty * IMB_anim_load_metadata(ImBufAnim *anim)
ImBufAnim * IMB_open_anim(const char *filepath, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
void IMB_close_anim(ImBufAnim *anim)
void IMB_close_anim_proxies(ImBufAnim *anim)
int IMB_anim_get_duration(ImBufAnim *anim, IMB_Timecode_Type tc)
void IMB_suffix_anim(ImBufAnim *anim, const char *suffix)
void colorspace_set_default_role(char *colorspace, int size, int role)
ColorSpace * colormanage_colorspace_get_named(const char *name)
draw_view in_light_buf[] float
FFMPEG_INLINE int64_t av_get_frame_duration_in_pts_units(const AVFrame *picture)
FFMPEG_INLINE size_t ffmpeg_get_buffer_alignment()
FFMPEG_INLINE int64_t timestamp_from_pts_or_dts(int64_t pts, int64_t dts)
FFMPEG_INLINE int64_t av_get_pts_from_frame(AVFrame *picture)
FFMPEG_INLINE int av_image_deinterlace(AVFrame *dst, const AVFrame *src, enum AVPixelFormat pix_fmt, int width, int height)
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void IMB_freeImBuf(ImBuf *)
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
void MEM_freeN(void *vmemh)
void *(* MEM_callocN)(size_t len, const char *str)
unsigned __int64 uint64_t
char filepath[IMB_FILEPATH_SIZE]
ImBufByteBuffer byte_buffer