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>
68 if (anim ==
nullptr) {
73 free_anim_ffmpeg(anim);
91 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"METADATA FETCH\n");
93 AVDictionaryEntry *entry =
nullptr;
95 entry = av_dict_get(anim->pFormatCtx->
metadata,
"", entry, AV_DICT_IGNORE_SUFFIX);
96 if (entry ==
nullptr) {
125 const int cicp[4] = {anim->pCodecCtx->color_primaries,
126 anim->pCodecCtx->color_trc,
128 anim->pCodecCtx->color_range};
132 if (colorspace ==
nullptr) {
143 const int streamindex,
144 const bool keep_original_colorspace,
151 anim = MEM_new<MovieReader>(
"anim struct");
152 if (anim !=
nullptr) {
159 if (colorspace && colorspace[0] !=
'\0') {
180#if !defined(WITH_FFMPEG)
185 if (anim->pCodecCtx !=
nullptr) {
199static double ffmpeg_stream_start_time_get(
const AVStream *stream)
201 if (stream->start_time == AV_NOPTS_VALUE) {
205 return stream->start_time * av_q2d(stream->time_base);
208static int ffmpeg_container_frame_count_get(
const AVFormatContext *pFormatCtx,
209 const AVStream *video_stream,
210 const double frame_rate)
217 const double video_start = ffmpeg_stream_start_time_get(video_stream);
218 double audio_start = 0;
220 for (
int i = 0;
i < pFormatCtx->nb_streams;
i++) {
221 if (pFormatCtx->streams[
i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
222 AVStream *audio_stream = pFormatCtx->streams[
i];
223 audio_start = ffmpeg_stream_start_time_get(audio_stream);
230 if (video_start > audio_start) {
231 stream_dur = double(pFormatCtx->duration) / AV_TIME_BASE - (video_start - audio_start);
237 stream_dur = double(pFormatCtx->duration) / AV_TIME_BASE;
240 return lround(stream_dur * frame_rate);
243static int ffmpeg_frame_count_get(
const AVFormatContext *pFormatCtx,
244 const AVStream *video_stream,
245 const double frame_rate)
248 if (video_stream->duration != AV_NOPTS_VALUE) {
249 const double stream_dur = video_stream->duration * av_q2d(video_stream->time_base);
250 return lround(stream_dur * frame_rate);
256 if (pFormatCtx->duration != AV_NOPTS_VALUE) {
257 return ffmpeg_container_frame_count_get(pFormatCtx, video_stream, frame_rate);
261 if (video_stream->nb_frames != 0) {
262 return video_stream->nb_frames;
269 BLI_assert(pFormatCtx->duration == AV_NOPTS_VALUE);
273static int calc_pix_fmt_max_component_bits(AVPixelFormat fmt)
275 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
276 if (desc ==
nullptr) {
280 for (
int i = 0;
i < desc->nb_components;
i++) {
281 bits =
max_ii(bits, desc->comp[
i].depth);
286static AVFormatContext *init_format_context(
const char *filepath,
287 int video_stream_index,
289 const AVCodec *forced_video_decoder)
291 AVFormatContext *format_ctx =
nullptr;
292 if (forced_video_decoder !=
nullptr) {
293 format_ctx = avformat_alloc_context();
294 format_ctx->video_codec_id = forced_video_decoder->id;
295 format_ctx->video_codec = forced_video_decoder;
298 if (avformat_open_input(&format_ctx, filepath,
nullptr,
nullptr) != 0) {
302 if (avformat_find_stream_info(format_ctx,
nullptr) < 0) {
303 avformat_close_input(&format_ctx);
307 av_dump_format(format_ctx, 0, filepath, 0);
311 for (
int i = 0;
i < format_ctx->nb_streams;
i++) {
312 if (format_ctx->streams[
i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
313 if (video_stream_index > 0) {
314 video_stream_index--;
322 if (r_stream_index == -1) {
323 avformat_close_input(&format_ctx);
330static AVFormatContext *init_format_context_vpx_workarounds(
const char *filepath,
331 int video_stream_index,
333 const AVCodec *&r_codec)
335 AVFormatContext *format_ctx = init_format_context(
336 filepath, video_stream_index, r_stream_index,
nullptr);
337 if (format_ctx ==
nullptr) {
348 const AVStream *video_stream = format_ctx->streams[r_stream_index];
349 if (
ELEM(video_stream->codecpar->codec_id, AV_CODEC_ID_VP8, AV_CODEC_ID_VP9)) {
350 AVDictionaryEntry *tag =
nullptr;
351 tag = av_dict_get(video_stream->metadata,
"alpha_mode", tag, AV_DICT_IGNORE_SUFFIX);
352 if (tag &&
STREQ(tag->value,
"1")) {
353 r_codec = avcodec_find_decoder_by_name(
354 video_stream->codecpar->codec_id == AV_CODEC_ID_VP8 ?
"libvpx" :
"libvpx-vp9");
355 if (r_codec !=
nullptr) {
356 avformat_close_input(&format_ctx);
357 format_ctx = avformat_alloc_context();
358 format_ctx = init_format_context(filepath, video_stream_index, r_stream_index, r_codec);
359 if (format_ctx ==
nullptr) {
366 if (r_codec ==
nullptr) {
368 r_codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
376 if (anim ==
nullptr) {
380 int video_stream_index;
381 const AVCodec *pCodec =
nullptr;
382 AVFormatContext *pFormatCtx = init_format_context_vpx_workarounds(
384 if (pFormatCtx ==
nullptr || pCodec ==
nullptr) {
385 avformat_close_input(&pFormatCtx);
389 AVCodecContext *pCodecCtx = avcodec_alloc_context3(
nullptr);
390 AVStream *video_stream = pFormatCtx->streams[video_stream_index];
391 avcodec_parameters_to_context(pCodecCtx, video_stream->codecpar);
392 pCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
394 if (pCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
395 pCodecCtx->thread_count = 0;
398 pCodecCtx->thread_count = MOV_thread_count();
401 if (pCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
402 pCodecCtx->thread_type = FF_THREAD_FRAME;
404 else if (pCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
405 pCodecCtx->thread_type = FF_THREAD_SLICE;
408 if (avcodec_open2(pCodecCtx, pCodec,
nullptr) < 0) {
409 avformat_close_input(&pFormatCtx);
412 if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) {
413 avcodec_free_context(&anim->pCodecCtx);
414 avformat_close_input(&pFormatCtx);
419 const bool is_ogg_container =
STREQ(pFormatCtx->iformat->name,
"ogg");
420 const bool is_non_ogg_video = video_stream->codecpar->codec_id != AV_CODEC_ID_THEORA;
421 const bool is_video_thumbnail = (video_stream->disposition & AV_DISPOSITION_ATTACHED_PIC) != 0;
422 anim->never_seek_decode_one_frame = is_ogg_container && is_non_ogg_video && is_video_thumbnail;
424 anim->frame_rate = av_guess_frame_rate(pFormatCtx, video_stream,
nullptr);
425 if (anim->never_seek_decode_one_frame) {
428 anim->frame_rate = {24, 1};
430 int frs_num = anim->frame_rate.num;
431 double frs_den = anim->frame_rate.den;
433 frs_den *= AV_TIME_BASE;
435 while (frs_num % 10 == 0 && frs_den >= 2.0 && frs_num > 10) {
444 anim->
start_offset = ffmpeg_stream_start_time_get(video_stream);
446 pFormatCtx, video_stream, av_q2d(anim->frame_rate));
448 anim->
x = pCodecCtx->width;
449 anim->
y = pCodecCtx->height;
453 anim->is_float = calc_pix_fmt_max_component_bits(pCodecCtx->pix_fmt) > 8;
455 anim->pFormatCtx = pFormatCtx;
456 anim->pCodecCtx = pCodecCtx;
457 anim->pCodec = pCodec;
458 anim->videoStream = video_stream_index;
462 anim->cur_key_frame_pts = -1;
463 anim->cur_packet = av_packet_alloc();
464 anim->cur_packet->stream_index = -1;
466 anim->pFrame = av_frame_alloc();
467 anim->pFrame_backup = av_frame_alloc();
468 anim->pFrame_backup_complete =
false;
469 anim->pFrame_complete =
false;
470 anim->pFrameDeinterlaced = av_frame_alloc();
471 anim->pFrameRGB = av_frame_alloc();
475 anim->pFrameRGB->format = anim->is_float ? AV_PIX_FMT_GBRAPF32LE : AV_PIX_FMT_RGBA;
476 anim->pFrameRGB->width = anim->
x;
477 anim->pFrameRGB->height = anim->
y;
480 if (av_frame_get_buffer(anim->pFrameRGB, align) < 0) {
482 avcodec_free_context(&anim->pCodecCtx);
483 avformat_close_input(&anim->pFormatCtx);
484 av_packet_free(&anim->cur_packet);
485 av_frame_free(&anim->pFrameRGB);
486 av_frame_free(&anim->pFrameDeinterlaced);
487 av_frame_free(&anim->pFrame);
488 av_frame_free(&anim->pFrame_backup);
489 anim->pCodecCtx =
nullptr;
494 anim->pFrameDeinterlaced->format = anim->pCodecCtx->pix_fmt;
495 anim->pFrameDeinterlaced->width = anim->pCodecCtx->width;
496 anim->pFrameDeinterlaced->height = anim->pCodecCtx->height;
497 av_image_fill_arrays(
498 anim->pFrameDeinterlaced->data,
499 anim->pFrameDeinterlaced->linesize,
501 av_image_get_buffer_size(
502 anim->pCodecCtx->pix_fmt, anim->pCodecCtx->width, anim->pCodecCtx->height, 1),
503 "ffmpeg deinterlace"),
504 anim->pCodecCtx->pix_fmt,
505 anim->pCodecCtx->width,
506 anim->pCodecCtx->height,
514 anim->img_convert_ctx = ffmpeg_sws_get_context(anim->
x,
516 anim->pCodecCtx->pix_fmt,
517 anim->pCodecCtx->color_range == AVCOL_RANGE_JPEG,
521 anim->pFrameRGB->format,
524 SWS_POINT | SWS_FULL_CHR_H_INT |
527 if (!anim->img_convert_ctx) {
529 "ffmpeg: swscale can't transform from pixel format %s to %s (%s)",
530 av_get_pix_fmt_name(anim->pCodecCtx->pix_fmt),
531 av_get_pix_fmt_name((AVPixelFormat)anim->pFrameRGB->format),
533 avcodec_free_context(&anim->pCodecCtx);
534 avformat_close_input(&anim->pFormatCtx);
535 av_packet_free(&anim->cur_packet);
536 av_frame_free(&anim->pFrameRGB);
537 av_frame_free(&anim->pFrameDeinterlaced);
538 av_frame_free(&anim->pFrame);
539 av_frame_free(&anim->pFrame_backup);
540 anim->pCodecCtx =
nullptr;
547static double ffmpeg_steps_per_frame_get(
const MovieReader *anim)
549 const AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
550 const AVRational time_base = v_st->time_base;
551 return av_q2d(av_inv_q(av_mul_q(anim->frame_rate, time_base)));
559static void ffmpeg_double_buffer_backup_frame_store(
MovieReader *anim,
int64_t pts_to_search)
562 if (anim->pFrame_backup_complete && anim->cur_pts >= pts_to_search) {
565 if (!anim->pFrame_complete) {
569 if (anim->pFrame_backup_complete) {
570 av_frame_unref(anim->pFrame_backup);
573 av_frame_move_ref(anim->pFrame_backup, anim->pFrame);
574 anim->pFrame_backup_complete =
true;
578static void ffmpeg_double_buffer_backup_frame_clear(
MovieReader *anim)
580 if (anim->pFrame_backup_complete) {
581 av_frame_unref(anim->pFrame_backup);
583 anim->pFrame_backup_complete =
false;
587static AVFrame *ffmpeg_double_buffer_frame_fallback_get(
MovieReader *anim)
589 av_log(anim->pFormatCtx, AV_LOG_ERROR,
"DECODE UNHAPPY: PTS not matched!\n");
591 if (anim->pFrame_complete) {
594 if (anim->pFrame_backup_complete) {
595 return anim->pFrame_backup;
602static void float_planar_to_interleaved(
const AVFrame *frame,
const int rotation,
ImBuf *ibuf)
605 const size_t src_linesize = frame->linesize[0];
606 BLI_assert_msg(frame->linesize[1] == src_linesize && frame->linesize[2] == src_linesize &&
607 frame->linesize[3] == src_linesize,
608 "ffmpeg frame should be 4 same size planes for a floating point image case");
610 const int size_x = ibuf->x;
611 const int size_y = ibuf->y;
612 if (rotation == 90) {
614 for (const int64_t y : y_range) {
615 int64_t src_offset = src_linesize * (size_y - y - 1);
616 const float *src_g = reinterpret_cast<const float *>(frame->data[0] + src_offset);
617 const float *src_b = reinterpret_cast<const float *>(frame->data[1] + src_offset);
618 const float *src_r = reinterpret_cast<const float *>(frame->data[2] + src_offset);
619 const float *src_a = reinterpret_cast<const float *>(frame->data[3] + src_offset);
620 float *dst = ibuf->float_buffer.data + (y + (size_x - 1) * size_y) * 4;
621 for (int x = 0; x < size_x; x++) {
630 else if (rotation == 180) {
633 int64_t src_offset = src_linesize * (size_y -
y - 1);
634 const float *src_g =
reinterpret_cast<const float *
>(frame->data[0] + src_offset);
635 const float *src_b =
reinterpret_cast<const float *
>(frame->data[1] + src_offset);
636 const float *src_r =
reinterpret_cast<const float *
>(frame->data[2] + src_offset);
637 const float *src_a =
reinterpret_cast<const float *
>(frame->data[3] + src_offset);
638 float *dst = ibuf->
float_buffer.
data + ((size_y -
y - 1) * size_x + size_x - 1) * 4;
639 for (
int x = 0;
x < size_x;
x++) {
648 else if (rotation == 270) {
651 int64_t src_offset = src_linesize * (size_y -
y - 1);
652 const float *src_g =
reinterpret_cast<const float *
>(frame->data[0] + src_offset);
653 const float *src_b =
reinterpret_cast<const float *
>(frame->data[1] + src_offset);
654 const float *src_r =
reinterpret_cast<const float *
>(frame->data[2] + src_offset);
655 const float *src_a =
reinterpret_cast<const float *
>(frame->data[3] + src_offset);
657 for (
int x = 0;
x < size_x;
x++) {
666 else if (rotation == 0) {
669 int64_t src_offset = src_linesize * (size_y -
y - 1);
670 const float *src_g =
reinterpret_cast<const float *
>(frame->data[0] + src_offset);
671 const float *src_b =
reinterpret_cast<const float *
>(frame->data[1] + src_offset);
672 const float *src_r =
reinterpret_cast<const float *
>(frame->data[2] + src_offset);
673 const float *src_a =
reinterpret_cast<const float *
>(frame->data[3] + src_offset);
675 for (
int x = 0;
x < size_x;
x++) {
685 if (
ELEM(rotation, 90, 270)) {
686 std::swap(ibuf->
x, ibuf->
y);
701 if (
input->data[0] ==
nullptr &&
input->data[1] ==
nullptr &&
input->data[2] ==
nullptr &&
702 input->data[3] ==
nullptr)
706 "data not read properly...");
710 av_log(anim->pFormatCtx,
712 " POSTPROC: AVFrame planes: %p %p %p %p\n",
719 if (ffmpeg_deinterlace(anim->pFrameDeinterlaced,
721 anim->pCodecCtx->pix_fmt,
722 anim->pCodecCtx->width,
723 anim->pCodecCtx->height) < 0)
728 input = anim->pFrameDeinterlaced;
732 bool already_rotated =
false;
733 if (anim->is_float) {
738 ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB,
input);
740 float_planar_to_interleaved(anim->pFrameRGB, anim->
video_rotation, ibuf);
741 already_rotated =
true;
748 const int ibuf_linesize = ibuf->
x * 4;
749 const int rgb_linesize = anim->pFrameRGB->linesize[0];
750 bool scale_to_ibuf = (rgb_linesize == ibuf_linesize);
754# if (defined(__aarch64__) || defined(_M_ARM64)) && (LIBSWSCALE_VERSION_MAJOR < 7)
755 scale_to_ibuf =
false;
757 uint8_t *rgb_data = anim->pFrameRGB->data[0];
762 anim->pFrameRGB->linesize[0] = -ibuf_linesize;
763 anim->pFrameRGB->data[0] = ibuf->
byte_buffer.
data + (ibuf->
y - 1) * ibuf_linesize;
765 ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB,
input);
767 anim->pFrameRGB->linesize[0] = rgb_linesize;
768 anim->pFrameRGB->data[0] = rgb_data;
772 ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB,
input);
775 const int src_linesize[4] = {-rgb_linesize, 0, 0, 0};
776 const uint8_t *
const src[4] = {
777 rgb_data + (anim->
y - 1) * rgb_linesize,
nullptr,
nullptr,
nullptr};
778 int dst_size = av_image_get_buffer_size(AVPixelFormat(anim->pFrameRGB->format),
779 anim->pFrameRGB->width,
780 anim->pFrameRGB->height,
786 AVPixelFormat(anim->pFrameRGB->format),
808 av_log(anim->pFormatCtx,
810 "DECODE HAPPY: %s frame PTS range %" PRId64 " - %" PRId64 ".\n",
818 return pts_start <= pts_to_search && pts_to_search < pts_end;
828 if (!anim->pFrame_complete) {
832 if (anim->never_seek_decode_one_frame) {
837 const bool backup_frame_ready = anim->pFrame_backup_complete;
842 AVFrame *best_frame =
nullptr;
843 if (ffmpeg_pts_isect(recent_start, recent_end, pts_to_search)) {
844 final_frame_log(anim, recent_start, recent_end,
"Recent");
845 best_frame = anim->pFrame;
847 else if (backup_frame_ready && ffmpeg_pts_isect(backup_start, recent_start, pts_to_search)) {
848 final_frame_log(anim, backup_start, recent_start,
"Backup");
849 best_frame = anim->pFrame_backup;
854static void ffmpeg_decode_store_frame_pts(
MovieReader *anim)
858# ifdef FFMPEG_OLD_KEY_FRAME_QUERY_METHOD
859 if (anim->pFrame->key_frame)
861 if (anim->pFrame->flags & AV_FRAME_FLAG_KEY)
864 anim->cur_key_frame_pts = anim->cur_pts;
867 av_log(anim->pFormatCtx,
869 " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
874static int ffmpeg_read_video_frame(
MovieReader *anim, AVPacket *packet)
877 while ((
ret = av_read_frame(anim->pFormatCtx, packet)) >= 0) {
878 if (packet->stream_index == anim->videoStream) {
881 av_packet_unref(packet);
882 packet->stream_index = -1;
889static int ffmpeg_decode_video_frame(
MovieReader *anim)
891 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
" DECODE VIDEO FRAME\n");
895 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
896 if (anim->pFrame_complete) {
897 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
" DECODE FROM CODEC BUFFER\n");
898 ffmpeg_decode_store_frame_pts(anim);
903 if (anim->cur_packet->stream_index == anim->videoStream) {
904 av_packet_unref(anim->cur_packet);
905 anim->cur_packet->stream_index = -1;
908 while ((rval = ffmpeg_read_video_frame(anim, anim->cur_packet)) >= 0) {
909 if (anim->cur_packet->stream_index != anim->videoStream) {
913 av_log(anim->pFormatCtx,
916 anim->cur_packet->stream_index,
917 (anim->cur_packet->dts == AV_NOPTS_VALUE) ? -1 :
int64_t(anim->cur_packet->dts),
918 (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 :
int64_t(anim->cur_packet->pts),
919 (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ?
" KEY" :
"");
921 avcodec_send_packet(anim->pCodecCtx, anim->cur_packet);
922 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
924 if (anim->pFrame_complete) {
925 ffmpeg_decode_store_frame_pts(anim);
928 av_packet_unref(anim->cur_packet);
929 anim->cur_packet->stream_index = -1;
932 if (rval == AVERROR_EOF) {
934 avcodec_send_packet(anim->pCodecCtx,
nullptr);
935 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
937 if (anim->pFrame_complete) {
938 ffmpeg_decode_store_frame_pts(anim);
944 av_packet_unref(anim->cur_packet);
945 anim->cur_packet->stream_index = -1;
947 char error_str[AV_ERROR_MAX_STRING_SIZE];
948 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, rval);
950 av_log(anim->pFormatCtx,
952 " DECODE READ FAILED: av_read_frame() "
953 "returned error: %s\n",
969 int64_t seek_pts = pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3);
971 seek_pts = std::max<int64_t>(seek_pts, 0);
986 pts_to_search = tc_index->
get_pts(new_frame_index);
989 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
990 int64_t start_pts = v_st->start_time;
992 pts_to_search =
round(position * ffmpeg_steps_per_frame_get(anim));
994 if (start_pts != AV_NOPTS_VALUE) {
995 pts_to_search += start_pts;
998 return pts_to_search;
1001static bool ffmpeg_is_first_frame_decode(
MovieReader *anim)
1003 return anim->pFrame_complete ==
false;
1010 av_log(anim->pFormatCtx,
1021 const int64_t start_gop_frame = anim->cur_key_frame_pts;
1022 bool decode_error =
false;
1024 while (!decode_error && anim->cur_pts < pts_to_search) {
1025 ffmpeg_scan_log(anim, pts_to_search);
1026 ffmpeg_double_buffer_backup_frame_store(anim, pts_to_search);
1027 decode_error = ffmpeg_decode_video_frame(anim) < 1;
1033 if (anim->seek_before_decode && start_gop_frame != anim->cur_key_frame_pts) {
1034 av_log(anim->pFormatCtx, AV_LOG_ERROR,
"SCAN: Frame belongs to an unexpected GOP!\n");
1043static int ffmpeg_generic_seek_workaround(
MovieReader *anim,
1047 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
1048 int64_t start_pts = v_st->start_time;
1049 int64_t current_pts = *requested_pts;
1056 while (current_pts != 0) {
1057 current_pts = *requested_pts -
int64_t(
round(offset * ffmpeg_steps_per_frame_get(anim)));
1058 current_pts = std::max(current_pts,
int64_t(0));
1061 if (av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD) < 0)
1067 AVPacket *read_packet = av_packet_alloc();
1068 while (av_read_frame(anim->pFormatCtx, read_packet) >= 0) {
1069 if (read_packet->stream_index == anim->videoStream) {
1072 av_packet_unref(read_packet);
1076 bool is_key_frame = read_packet->flags & AV_PKT_FLAG_KEY;
1081 av_packet_free(&read_packet);
1084 if (cur_pts <= pts_to_search) {
1091 if (cur_pts <= start_pts) {
1099 *requested_pts = current_pts;
1102 return av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD);
1107static void ffmpeg_seek_recover_stream_position(
MovieReader *anim)
1109 AVPacket *temp_packet = av_packet_alloc();
1110 while (ffmpeg_read_video_frame(anim, temp_packet) >= 0) {
1113 av_packet_unref(temp_packet);
1115 if (current_pts == temp_pts) {
1119 av_packet_free(&temp_packet);
1123static bool ffmpeg_seek_buffers_need_flushing(
MovieReader *anim,
int position,
int64_t seek_pos)
1126 AVPacket *temp_packet = av_packet_alloc();
1127 ffmpeg_read_video_frame(anim, temp_packet);
1129 av_packet_unref(temp_packet);
1130 av_packet_free(&temp_packet);
1140 if (gop_pts == anim->cur_key_frame_pts && position > anim->
cur_position) {
1141 ffmpeg_seek_recover_stream_position(anim);
1146 av_seek_frame(anim->pFormatCtx, anim->videoStream, seek_pos, AVSEEK_FLAG_BACKWARD);
1147 anim->cur_key_frame_pts = gop_pts;
1152static int ffmpeg_seek_to_key_frame(
MovieReader *anim,
1169 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"TC INDEX seek pts = %" PRIu64 "\n", pts);
1170 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"TC INDEX seek dts = %" PRIu64 "\n", dts);
1172 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"Using PTS from timecode as seek_pos\n");
1173 ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, pts, AVSEEK_FLAG_BACKWARD);
1178 seek_pos = ffmpeg_get_seek_pts(anim, pts_to_search);
1180 anim->pFormatCtx, AV_LOG_DEBUG,
"NO INDEX final seek seek_pos = %" PRId64 "\n", seek_pos);
1182 AVFormatContext *format_ctx = anim->pFormatCtx;
1187 if (!(format_ctx->iformat->flags & AVFMT_TS_DISCONT)) {
1188 ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, seek_pos, AVSEEK_FLAG_BACKWARD);
1191 ret = ffmpeg_generic_seek_workaround(anim, &seek_pos, pts_to_search);
1192 av_log(anim->pFormatCtx,
1194 "Adjusted final seek seek_pos = %" PRId64 "\n",
1198 if (
ret <= 0 && !ffmpeg_seek_buffers_need_flushing(anim, position, seek_pos)) {
1204 av_log(anim->pFormatCtx,
1207 "error while seeking to DTS = %" PRId64 " (frameno = %d, PTS = %" PRId64
1208 "): errcode = %d\n",
1216 avcodec_flush_buffers(anim->pCodecCtx);
1217 ffmpeg_double_buffer_backup_frame_clear(anim);
1221 if (anim->cur_packet->stream_index == anim->videoStream) {
1222 av_packet_unref(anim->cur_packet);
1223 anim->cur_packet->stream_index = -1;
1229static bool ffmpeg_must_decode(
MovieReader *anim,
int position)
1231 return !anim->pFrame_complete || anim->
cur_position != position;
1234static bool ffmpeg_must_seek(
MovieReader *anim,
int position)
1236 bool must_seek = position != anim->
cur_position + 1 || ffmpeg_is_first_frame_decode(anim);
1237 anim->seek_before_decode = must_seek;
1243 if (anim ==
nullptr) {
1247 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"FETCH: seek_pos=%d\n", position);
1250 int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
1251 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
1252 double frame_rate = av_q2d(v_st->r_frame_rate);
1253 double pts_time_base = av_q2d(v_st->time_base);
1254 int64_t start_pts = v_st->start_time;
1256 if (anim->never_seek_decode_one_frame) {
1258 if (!anim->pFrame_complete) {
1259 ffmpeg_decode_video_frame(anim);
1264 av_log(anim->pFormatCtx,
1266 "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, start_pts=%" PRId64
1273 if (ffmpeg_must_decode(anim, position)) {
1274 if (ffmpeg_must_seek(anim, position)) {
1275 ffmpeg_seek_to_key_frame(anim, position, tc_index, pts_to_search);
1278 ffmpeg_decode_video_frame_scan(anim, pts_to_search);
1283 anim->
x = anim->pCodecCtx->width;
1284 anim->
y = anim->pCodecCtx->height;
1286 const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt);
1289 if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) {
1297 const size_t pixel_size = anim->is_float ? 16 : 4;
1300 if (anim->is_float) {
1307 AVFrame *final_frame = ffmpeg_frame_by_pts_get(anim, pts_to_search);
1308 if (final_frame ==
nullptr) {
1311 final_frame = ffmpeg_double_buffer_frame_fallback_get(anim);
1316 if (final_frame !=
nullptr) {
1317 ffmpeg_postprocess(anim, final_frame, cur_frame_final);
1320 if (anim->is_float) {
1347 return cur_frame_final;
1352 if (anim ==
nullptr) {
1356 if (anim->pCodecCtx) {
1357 avcodec_free_context(&anim->pCodecCtx);
1358 avformat_close_input(&anim->pFormatCtx);
1359 av_packet_free(&anim->cur_packet);
1361 av_frame_free(&anim->pFrame);
1362 av_frame_free(&anim->pFrame_backup);
1363 av_frame_free(&anim->pFrameRGB);
1364 if (anim->pFrameDeinterlaced->data[0] !=
nullptr) {
1365 MEM_freeN(anim->pFrameDeinterlaced->data[0]);
1367 av_frame_free(&anim->pFrameDeinterlaced);
1368 ffmpeg_sws_release_context(anim->img_convert_ctx);
1381 if (anim ==
nullptr) {
1389 free_anim_ffmpeg(anim);
1390 if (startffmpeg(anim)) {
1401 ImBuf *ibuf =
nullptr;
1420 if (anim->pFormatCtx) {
1421 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
1422 AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st,
nullptr);
1423 if (frame_rate.num != 0) {
1442 ImBuf *ibuf =
nullptr;
1443 if (anim ==
nullptr) {
1473 ibuf = ffmpeg_fetchibuf(anim, position, tc);
1517 if (anim->
frs_sec > SHRT_MAX) {
1519 r_fps_num = SHRT_MAX;
blender::ocio::ColorSpace ColorSpace
#define BLI_assert_msg(a, msg)
MINLINE int max_ii(int a, int b)
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
char * STRNCPY(char(&dst)[N], const char *src)
#define SNPRINTF_UTF8(dst, format,...)
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
#define CLOG_ERROR(clg_ref,...)
@ COLOR_ROLE_DEFAULT_BYTE
const char * IMB_colormanagement_colorspace_get_name(const ColorSpace *colorspace)
const char * IMB_colormanagement_role_colorspace_name_get(int role)
const ColorSpace * IMB_colormanagement_space_from_cicp(const int cicp[4], const ColorManagedFileOutput output)
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
void IMB_freeImBuf(ImBuf *ibuf)
bool IMB_rotate_orthogonal(ImBuf *ibuf, int degrees)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_filtery(ImBuf *ibuf)
void IMB_assign_byte_buffer(ImBuf *ibuf, uint8_t *buffer_data, ImBufOwnership ownership)
Read Guarded memory(de)allocation.
unsigned long long int uint64_t
const ColorSpace * colormanage_colorspace_get_named(const char *name)
void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace, const ColorManagedFileOutput output)
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 ffmpeg_get_video_rotation(const AVStream *stream)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
void MEM_freeN(void *vmemh)
const MovieIndex * movie_open_index(MovieReader *anim, IMB_Timecode_Type tc)
void MOV_close_proxies(MovieReader *anim)
int MOV_calc_frame_index_with_timecode(MovieReader *anim, IMB_Timecode_Type tc, int position)
MovieReader * movie_open_proxy(MovieReader *anim, IMB_Proxy_Size preview_size)
static bool anim_getnew(MovieReader *anim)
ImBuf * MOV_decode_preview_frame(MovieReader *anim)
void MOV_close(MovieReader *anim)
double MOV_get_start_offset_seconds(const MovieReader *anim)
int MOV_get_duration_frames(MovieReader *anim, IMB_Timecode_Type tc)
static void probe_video_colorspace(MovieReader *anim, char r_colorspace_name[IM_MAX_SPACE])
bool MOV_is_initialized_and_valid(const MovieReader *anim)
void MOV_get_filename(const MovieReader *anim, char *filename, int filename_maxncpy)
MovieReader * MOV_open_file(const char *filepath, const int ib_flags, const int streamindex, const bool keep_original_colorspace, char colorspace[IM_MAX_SPACE])
void MOV_set_multiview_suffix(MovieReader *anim, const char *suffix)
int MOV_get_image_width(const MovieReader *anim)
float MOV_get_fps(const MovieReader *anim)
IDProperty * MOV_load_metadata(MovieReader *anim)
ImBuf * MOV_decode_frame(MovieReader *anim, int position, IMB_Timecode_Type tc, IMB_Proxy_Size preview_size)
bool MOV_get_fps_num_denom(const MovieReader *anim, short &r_fps_num, float &r_fps_denom)
int MOV_get_image_height(const MovieReader *anim)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
const ColorSpace * colorspace
const ColorSpace * colorspace
char filepath[IMB_FILEPATH_SIZE]
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
int get_frame_index(int frameno) const
uint64_t get_seek_pos_dts(int frame_index) const
uint64_t get_pts(int frame_index) const
uint64_t get_seek_pos_pts(int frame_index) const
bool keep_original_colorspace