43# include <libavcodec/avcodec.h>
44# include <libavformat/avformat.h>
45# include <libavutil/imgutils.h>
46# include <libavutil/rational.h>
47# include <libswscale/swscale.h>
60 if (anim ==
nullptr) {
65 free_anim_ffmpeg(anim);
83 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"METADATA FETCH\n");
85 AVDictionaryEntry *entry =
nullptr;
87 entry = av_dict_get(anim->pFormatCtx->
metadata,
"", entry, AV_DICT_IGNORE_SUFFIX);
88 if (entry ==
nullptr) {
110 anim = MEM_new<MovieReader>(
"anim struct");
111 if (anim !=
nullptr) {
115 if (colorspace && colorspace[0] ==
'\0') {
131#if !defined(WITH_FFMPEG)
136 if (anim->pCodecCtx !=
nullptr) {
150static double ffmpeg_stream_start_time_get(
const AVStream *stream)
152 if (stream->start_time == AV_NOPTS_VALUE) {
156 return stream->start_time * av_q2d(stream->time_base);
159static int ffmpeg_container_frame_count_get(
const AVFormatContext *pFormatCtx,
160 const AVStream *video_stream,
161 const double frame_rate)
168 const double video_start = ffmpeg_stream_start_time_get(video_stream);
169 double audio_start = 0;
171 for (
int i = 0;
i < pFormatCtx->nb_streams;
i++) {
172 if (pFormatCtx->streams[
i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
173 AVStream *audio_stream = pFormatCtx->streams[
i];
174 audio_start = ffmpeg_stream_start_time_get(audio_stream);
181 if (video_start > audio_start) {
182 stream_dur = double(pFormatCtx->duration) / AV_TIME_BASE - (video_start - audio_start);
188 stream_dur = double(pFormatCtx->duration) / AV_TIME_BASE;
191 return lround(stream_dur * frame_rate);
194static int ffmpeg_frame_count_get(
const AVFormatContext *pFormatCtx,
195 const AVStream *video_stream,
196 const double frame_rate)
199 if (video_stream->duration != AV_NOPTS_VALUE) {
200 const double stream_dur = video_stream->duration * av_q2d(video_stream->time_base);
201 return lround(stream_dur * frame_rate);
207 if (pFormatCtx->duration != AV_NOPTS_VALUE) {
208 return ffmpeg_container_frame_count_get(pFormatCtx, video_stream, frame_rate);
212 if (video_stream->nb_frames != 0) {
213 return video_stream->nb_frames;
220 BLI_assert(pFormatCtx->duration == AV_NOPTS_VALUE);
224static int calc_pix_fmt_max_component_bits(AVPixelFormat fmt)
226 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
227 if (desc ==
nullptr) {
231 for (
int i = 0;
i < desc->nb_components;
i++) {
232 bits =
max_ii(bits, desc->comp[
i].depth);
237static AVFormatContext *init_format_context(
const char *filepath,
238 int video_stream_index,
240 const AVCodec *forced_video_decoder)
242 AVFormatContext *format_ctx =
nullptr;
243 if (forced_video_decoder !=
nullptr) {
244 format_ctx = avformat_alloc_context();
245 format_ctx->video_codec_id = forced_video_decoder->id;
246 format_ctx->video_codec = forced_video_decoder;
249 if (avformat_open_input(&format_ctx, filepath,
nullptr,
nullptr) != 0) {
253 if (avformat_find_stream_info(format_ctx,
nullptr) < 0) {
254 avformat_close_input(&format_ctx);
258 av_dump_format(format_ctx, 0, filepath, 0);
262 for (
int i = 0;
i < format_ctx->nb_streams;
i++) {
263 if (format_ctx->streams[
i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
264 if (video_stream_index > 0) {
265 video_stream_index--;
273 if (r_stream_index == -1) {
274 avformat_close_input(&format_ctx);
281static AVFormatContext *init_format_context_vpx_workarounds(
const char *filepath,
282 int video_stream_index,
284 const AVCodec *&r_codec)
286 AVFormatContext *format_ctx = init_format_context(
287 filepath, video_stream_index, r_stream_index,
nullptr);
288 if (format_ctx ==
nullptr) {
299 const AVStream *video_stream = format_ctx->streams[r_stream_index];
300 if (
ELEM(video_stream->codecpar->codec_id, AV_CODEC_ID_VP8, AV_CODEC_ID_VP9)) {
301 AVDictionaryEntry *tag =
nullptr;
302 tag = av_dict_get(video_stream->metadata,
"alpha_mode", tag, AV_DICT_IGNORE_SUFFIX);
303 if (tag &&
STREQ(tag->value,
"1")) {
304 r_codec = avcodec_find_decoder_by_name(
305 video_stream->codecpar->codec_id == AV_CODEC_ID_VP8 ?
"libvpx" :
"libvpx-vp9");
306 if (r_codec !=
nullptr) {
307 avformat_close_input(&format_ctx);
308 format_ctx = avformat_alloc_context();
309 format_ctx = init_format_context(filepath, video_stream_index, r_stream_index, r_codec);
310 if (format_ctx ==
nullptr) {
317 if (r_codec ==
nullptr) {
319 r_codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
327 if (anim ==
nullptr) {
331 int video_stream_index;
332 const AVCodec *pCodec =
nullptr;
333 AVFormatContext *pFormatCtx = init_format_context_vpx_workarounds(
335 if (pFormatCtx ==
nullptr || pCodec ==
nullptr) {
336 avformat_close_input(&pFormatCtx);
340 AVCodecContext *pCodecCtx = avcodec_alloc_context3(
nullptr);
341 AVStream *video_stream = pFormatCtx->streams[video_stream_index];
342 avcodec_parameters_to_context(pCodecCtx, video_stream->codecpar);
343 pCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
345 if (pCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS) {
346 pCodecCtx->thread_count = 0;
352 if (pCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS) {
353 pCodecCtx->thread_type = FF_THREAD_FRAME;
355 else if (pCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS) {
356 pCodecCtx->thread_type = FF_THREAD_SLICE;
359 if (avcodec_open2(pCodecCtx, pCodec,
nullptr) < 0) {
360 avformat_close_input(&pFormatCtx);
363 if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) {
364 avcodec_free_context(&anim->pCodecCtx);
365 avformat_close_input(&pFormatCtx);
370 const bool is_ogg_container =
STREQ(pFormatCtx->iformat->name,
"ogg");
371 const bool is_non_ogg_video = video_stream->codecpar->codec_id != AV_CODEC_ID_THEORA;
372 const bool is_video_thumbnail = (video_stream->disposition & AV_DISPOSITION_ATTACHED_PIC) != 0;
373 anim->never_seek_decode_one_frame = is_ogg_container && is_non_ogg_video && is_video_thumbnail;
375 anim->frame_rate = av_guess_frame_rate(pFormatCtx, video_stream,
nullptr);
376 if (anim->never_seek_decode_one_frame) {
379 anim->frame_rate = {24, 1};
381 int frs_num = anim->frame_rate.num;
382 double frs_den = anim->frame_rate.den;
384 frs_den *= AV_TIME_BASE;
386 while (frs_num % 10 == 0 && frs_den >= 2.0 && frs_num > 10) {
395 anim->
start_offset = ffmpeg_stream_start_time_get(video_stream);
397 pFormatCtx, video_stream, av_q2d(anim->frame_rate));
399 anim->
x = pCodecCtx->width;
400 anim->
y = pCodecCtx->height;
404 anim->is_float = calc_pix_fmt_max_component_bits(pCodecCtx->pix_fmt) > 8;
406 anim->pFormatCtx = pFormatCtx;
407 anim->pCodecCtx = pCodecCtx;
408 anim->pCodec = pCodec;
409 anim->videoStream = video_stream_index;
413 anim->cur_key_frame_pts = -1;
414 anim->cur_packet = av_packet_alloc();
415 anim->cur_packet->stream_index = -1;
417 anim->pFrame = av_frame_alloc();
418 anim->pFrame_backup = av_frame_alloc();
419 anim->pFrame_backup_complete =
false;
420 anim->pFrame_complete =
false;
421 anim->pFrameDeinterlaced = av_frame_alloc();
422 anim->pFrameRGB = av_frame_alloc();
426 anim->pFrameRGB->format = anim->is_float ? AV_PIX_FMT_GBRAPF32LE : AV_PIX_FMT_RGBA;
427 anim->pFrameRGB->width = anim->
x;
428 anim->pFrameRGB->height = anim->
y;
431 if (av_frame_get_buffer(anim->pFrameRGB, align) < 0) {
432 fprintf(stderr,
"Could not allocate frame data.\n");
433 avcodec_free_context(&anim->pCodecCtx);
434 avformat_close_input(&anim->pFormatCtx);
435 av_packet_free(&anim->cur_packet);
436 av_frame_free(&anim->pFrameRGB);
437 av_frame_free(&anim->pFrameDeinterlaced);
438 av_frame_free(&anim->pFrame);
439 av_frame_free(&anim->pFrame_backup);
440 anim->pCodecCtx =
nullptr;
445 anim->pFrameDeinterlaced->format = anim->pCodecCtx->pix_fmt;
446 anim->pFrameDeinterlaced->width = anim->pCodecCtx->width;
447 anim->pFrameDeinterlaced->height = anim->pCodecCtx->height;
448 av_image_fill_arrays(
449 anim->pFrameDeinterlaced->data,
450 anim->pFrameDeinterlaced->linesize,
452 av_image_get_buffer_size(
453 anim->pCodecCtx->pix_fmt, anim->pCodecCtx->width, anim->pCodecCtx->height, 1),
454 "ffmpeg deinterlace"),
455 anim->pCodecCtx->pix_fmt,
456 anim->pCodecCtx->width,
457 anim->pCodecCtx->height,
465 anim->img_convert_ctx = ffmpeg_sws_get_context(anim->
x,
467 anim->pCodecCtx->pix_fmt,
468 anim->pCodecCtx->color_range == AVCOL_RANGE_JPEG,
472 anim->pFrameRGB->format,
475 SWS_POINT | SWS_FULL_CHR_H_INT |
478 if (!anim->img_convert_ctx) {
480 "ffmpeg: swscale can't transform from pixel format %s to %s (%s)\n",
481 av_get_pix_fmt_name(anim->pCodecCtx->pix_fmt),
482 av_get_pix_fmt_name((AVPixelFormat)anim->pFrameRGB->format),
484 avcodec_free_context(&anim->pCodecCtx);
485 avformat_close_input(&anim->pFormatCtx);
486 av_packet_free(&anim->cur_packet);
487 av_frame_free(&anim->pFrameRGB);
488 av_frame_free(&anim->pFrameDeinterlaced);
489 av_frame_free(&anim->pFrame);
490 av_frame_free(&anim->pFrame_backup);
491 anim->pCodecCtx =
nullptr;
498static double ffmpeg_steps_per_frame_get(
const MovieReader *anim)
500 const AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
501 const AVRational time_base = v_st->time_base;
502 return av_q2d(av_inv_q(av_mul_q(anim->frame_rate, time_base)));
510static void ffmpeg_double_buffer_backup_frame_store(
MovieReader *anim,
int64_t pts_to_search)
513 if (anim->pFrame_backup_complete && anim->cur_pts >= pts_to_search) {
516 if (!anim->pFrame_complete) {
520 if (anim->pFrame_backup_complete) {
521 av_frame_unref(anim->pFrame_backup);
524 av_frame_move_ref(anim->pFrame_backup, anim->pFrame);
525 anim->pFrame_backup_complete =
true;
529static void ffmpeg_double_buffer_backup_frame_clear(
MovieReader *anim)
531 if (anim->pFrame_backup_complete) {
532 av_frame_unref(anim->pFrame_backup);
534 anim->pFrame_backup_complete =
false;
538static AVFrame *ffmpeg_double_buffer_frame_fallback_get(
MovieReader *anim)
540 av_log(anim->pFormatCtx, AV_LOG_ERROR,
"DECODE UNHAPPY: PTS not matched!\n");
542 if (anim->pFrame_complete) {
545 if (anim->pFrame_backup_complete) {
546 return anim->pFrame_backup;
553static void float_planar_to_interleaved(
const AVFrame *frame,
const int rotation,
ImBuf *ibuf)
556 const size_t src_linesize = frame->linesize[0];
557 BLI_assert_msg(frame->linesize[1] == src_linesize && frame->linesize[2] == src_linesize &&
558 frame->linesize[3] == src_linesize,
559 "ffmpeg frame should be 4 same size planes for a floating point image case");
561 const int size_x = ibuf->x;
562 const int size_y = ibuf->y;
563 if (rotation == 90) {
565 for (const int64_t y : y_range) {
566 int64_t src_offset = src_linesize * (size_y - y - 1);
567 const float *src_g = reinterpret_cast<const float *>(frame->data[0] + src_offset);
568 const float *src_b = reinterpret_cast<const float *>(frame->data[1] + src_offset);
569 const float *src_r = reinterpret_cast<const float *>(frame->data[2] + src_offset);
570 const float *src_a = reinterpret_cast<const float *>(frame->data[3] + src_offset);
571 float *dst = ibuf->float_buffer.data + (y + (size_x - 1) * size_y) * 4;
572 for (int x = 0; x < size_x; x++) {
581 else if (rotation == 180) {
584 int64_t src_offset = src_linesize * (size_y -
y - 1);
585 const float *src_g =
reinterpret_cast<const float *
>(frame->data[0] + src_offset);
586 const float *src_b =
reinterpret_cast<const float *
>(frame->data[1] + src_offset);
587 const float *src_r =
reinterpret_cast<const float *
>(frame->data[2] + src_offset);
588 const float *src_a =
reinterpret_cast<const float *
>(frame->data[3] + src_offset);
589 float *dst = ibuf->
float_buffer.
data + ((size_y -
y - 1) * size_x + size_x - 1) * 4;
590 for (
int x = 0;
x < size_x;
x++) {
599 else if (rotation == 270) {
602 int64_t src_offset = src_linesize * (size_y -
y - 1);
603 const float *src_g =
reinterpret_cast<const float *
>(frame->data[0] + src_offset);
604 const float *src_b =
reinterpret_cast<const float *
>(frame->data[1] + src_offset);
605 const float *src_r =
reinterpret_cast<const float *
>(frame->data[2] + src_offset);
606 const float *src_a =
reinterpret_cast<const float *
>(frame->data[3] + src_offset);
608 for (
int x = 0;
x < size_x;
x++) {
617 else if (rotation == 0) {
620 int64_t src_offset = src_linesize * (size_y -
y - 1);
621 const float *src_g =
reinterpret_cast<const float *
>(frame->data[0] + src_offset);
622 const float *src_b =
reinterpret_cast<const float *
>(frame->data[1] + src_offset);
623 const float *src_r =
reinterpret_cast<const float *
>(frame->data[2] + src_offset);
624 const float *src_a =
reinterpret_cast<const float *
>(frame->data[3] + src_offset);
626 for (
int x = 0;
x < size_x;
x++) {
636 if (
ELEM(rotation, 90, 270)) {
637 std::swap(ibuf->
x, ibuf->
y);
652 if (
input->data[0] ==
nullptr &&
input->data[1] ==
nullptr &&
input->data[2] ==
nullptr &&
653 input->data[3] ==
nullptr)
657 "data not read properly...\n");
661 av_log(anim->pFormatCtx,
663 " POSTPROC: AVFrame planes: %p %p %p %p\n",
670 if (ffmpeg_deinterlace(anim->pFrameDeinterlaced,
672 anim->pCodecCtx->pix_fmt,
673 anim->pCodecCtx->width,
674 anim->pCodecCtx->height) < 0)
679 input = anim->pFrameDeinterlaced;
683 bool already_rotated =
false;
684 if (anim->is_float) {
689 ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB,
input);
691 float_planar_to_interleaved(anim->pFrameRGB, anim->
video_rotation, ibuf);
692 already_rotated =
true;
699 const int ibuf_linesize = ibuf->
x * 4;
700 const int rgb_linesize = anim->pFrameRGB->linesize[0];
701 bool scale_to_ibuf = (rgb_linesize == ibuf_linesize);
705# if (defined(__aarch64__) || defined(_M_ARM64)) && (LIBSWSCALE_VERSION_MAJOR < 7)
706 scale_to_ibuf =
false;
708 uint8_t *rgb_data = anim->pFrameRGB->data[0];
713 anim->pFrameRGB->linesize[0] = -ibuf_linesize;
714 anim->pFrameRGB->data[0] = ibuf->
byte_buffer.
data + (ibuf->
y - 1) * ibuf_linesize;
716 ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB,
input);
718 anim->pFrameRGB->linesize[0] = rgb_linesize;
719 anim->pFrameRGB->data[0] = rgb_data;
723 ffmpeg_sws_scale_frame(anim->img_convert_ctx, anim->pFrameRGB,
input);
726 const int src_linesize[4] = {-rgb_linesize, 0, 0, 0};
727 const uint8_t *
const src[4] = {
728 rgb_data + (anim->
y - 1) * rgb_linesize,
nullptr,
nullptr,
nullptr};
729 int dst_size = av_image_get_buffer_size(AVPixelFormat(anim->pFrameRGB->format),
730 anim->pFrameRGB->width,
731 anim->pFrameRGB->height,
737 AVPixelFormat(anim->pFrameRGB->format),
759 av_log(anim->pFormatCtx,
761 "DECODE HAPPY: %s frame PTS range %" PRId64 " - %" PRId64 ".\n",
769 return pts_start <= pts_to_search && pts_to_search < pts_end;
779 if (!anim->pFrame_complete) {
783 if (anim->never_seek_decode_one_frame) {
788 const bool backup_frame_ready = anim->pFrame_backup_complete;
793 AVFrame *best_frame =
nullptr;
794 if (ffmpeg_pts_isect(recent_start, recent_end, pts_to_search)) {
795 final_frame_log(anim, recent_start, recent_end,
"Recent");
796 best_frame = anim->pFrame;
798 else if (backup_frame_ready && ffmpeg_pts_isect(backup_start, recent_start, pts_to_search)) {
799 final_frame_log(anim, backup_start, recent_start,
"Backup");
800 best_frame = anim->pFrame_backup;
805static void ffmpeg_decode_store_frame_pts(
MovieReader *anim)
809# ifdef FFMPEG_OLD_KEY_FRAME_QUERY_METHOD
810 if (anim->pFrame->key_frame)
812 if (anim->pFrame->flags & AV_FRAME_FLAG_KEY)
815 anim->cur_key_frame_pts = anim->cur_pts;
818 av_log(anim->pFormatCtx,
820 " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n",
825static int ffmpeg_read_video_frame(
MovieReader *anim, AVPacket *packet)
828 while ((
ret = av_read_frame(anim->pFormatCtx, packet)) >= 0) {
829 if (packet->stream_index == anim->videoStream) {
832 av_packet_unref(packet);
833 packet->stream_index = -1;
840static int ffmpeg_decode_video_frame(
MovieReader *anim)
842 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
" DECODE VIDEO FRAME\n");
846 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
847 if (anim->pFrame_complete) {
848 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
" DECODE FROM CODEC BUFFER\n");
849 ffmpeg_decode_store_frame_pts(anim);
854 if (anim->cur_packet->stream_index == anim->videoStream) {
855 av_packet_unref(anim->cur_packet);
856 anim->cur_packet->stream_index = -1;
859 while ((rval = ffmpeg_read_video_frame(anim, anim->cur_packet)) >= 0) {
860 if (anim->cur_packet->stream_index != anim->videoStream) {
864 av_log(anim->pFormatCtx,
867 anim->cur_packet->stream_index,
868 (anim->cur_packet->dts == AV_NOPTS_VALUE) ? -1 :
int64_t(anim->cur_packet->dts),
869 (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 :
int64_t(anim->cur_packet->pts),
870 (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ?
" KEY" :
"");
872 avcodec_send_packet(anim->pCodecCtx, anim->cur_packet);
873 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
875 if (anim->pFrame_complete) {
876 ffmpeg_decode_store_frame_pts(anim);
879 av_packet_unref(anim->cur_packet);
880 anim->cur_packet->stream_index = -1;
883 if (rval == AVERROR_EOF) {
885 avcodec_send_packet(anim->pCodecCtx,
nullptr);
886 anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
888 if (anim->pFrame_complete) {
889 ffmpeg_decode_store_frame_pts(anim);
895 av_packet_unref(anim->cur_packet);
896 anim->cur_packet->stream_index = -1;
898 char error_str[AV_ERROR_MAX_STRING_SIZE];
899 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, rval);
901 av_log(anim->pFormatCtx,
903 " DECODE READ FAILED: av_read_frame() "
904 "returned error: %s\n",
920 int64_t seek_pts = pts_to_search - (ffmpeg_steps_per_frame_get(anim) * 3);
922 seek_pts = std::max<int64_t>(seek_pts, 0);
937 pts_to_search = tc_index->
get_pts(new_frame_index);
940 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
941 int64_t start_pts = v_st->start_time;
943 pts_to_search =
round(position * ffmpeg_steps_per_frame_get(anim));
945 if (start_pts != AV_NOPTS_VALUE) {
946 pts_to_search += start_pts;
949 return pts_to_search;
952static bool ffmpeg_is_first_frame_decode(
MovieReader *anim)
954 return anim->pFrame_complete ==
false;
961 av_log(anim->pFormatCtx,
972 const int64_t start_gop_frame = anim->cur_key_frame_pts;
973 bool decode_error =
false;
975 while (!decode_error && anim->cur_pts < pts_to_search) {
976 ffmpeg_scan_log(anim, pts_to_search);
977 ffmpeg_double_buffer_backup_frame_store(anim, pts_to_search);
978 decode_error = ffmpeg_decode_video_frame(anim) < 1;
984 if (anim->seek_before_decode && start_gop_frame != anim->cur_key_frame_pts) {
985 av_log(anim->pFormatCtx, AV_LOG_ERROR,
"SCAN: Frame belongs to an unexpected GOP!\n");
994static int ffmpeg_generic_seek_workaround(
MovieReader *anim,
998 int64_t current_pts = *requested_pts;
1001 int64_t cur_pts, prev_pts = -1;
1004 while (current_pts != 0) {
1005 current_pts = *requested_pts -
int64_t(
round(offset * ffmpeg_steps_per_frame_get(anim)));
1006 current_pts = std::max(current_pts,
int64_t(0));
1009 if (av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD) < 0)
1015 AVPacket *read_packet = av_packet_alloc();
1016 while (av_read_frame(anim->pFormatCtx, read_packet) >= 0) {
1017 if (read_packet->stream_index == anim->videoStream) {
1020 av_packet_unref(read_packet);
1024 bool is_key_frame = read_packet->flags & AV_PKT_FLAG_KEY;
1029 av_packet_free(&read_packet);
1032 if (cur_pts <= pts_to_search) {
1038 if (cur_pts == prev_pts) {
1048 *requested_pts = current_pts;
1051 return av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD);
1056static void ffmpeg_seek_recover_stream_position(
MovieReader *anim)
1058 AVPacket *temp_packet = av_packet_alloc();
1059 while (ffmpeg_read_video_frame(anim, temp_packet) >= 0) {
1062 av_packet_unref(temp_packet);
1064 if (current_pts == temp_pts) {
1068 av_packet_free(&temp_packet);
1072static bool ffmpeg_seek_buffers_need_flushing(
MovieReader *anim,
int position,
int64_t seek_pos)
1075 AVPacket *temp_packet = av_packet_alloc();
1076 ffmpeg_read_video_frame(anim, temp_packet);
1078 av_packet_unref(temp_packet);
1079 av_packet_free(&temp_packet);
1089 if (gop_pts == anim->cur_key_frame_pts && position > anim->
cur_position) {
1090 ffmpeg_seek_recover_stream_position(anim);
1095 av_seek_frame(anim->pFormatCtx, anim->videoStream, seek_pos, AVSEEK_FLAG_BACKWARD);
1096 anim->cur_key_frame_pts = gop_pts;
1101static int ffmpeg_seek_to_key_frame(
MovieReader *anim,
1118 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"TC INDEX seek pts = %" PRIu64 "\n", pts);
1119 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"TC INDEX seek dts = %" PRIu64 "\n", dts);
1121 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"Using PTS from timecode as seek_pos\n");
1122 ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, pts, AVSEEK_FLAG_BACKWARD);
1127 seek_pos = ffmpeg_get_seek_pts(anim, pts_to_search);
1129 anim->pFormatCtx, AV_LOG_DEBUG,
"NO INDEX final seek seek_pos = %" PRId64 "\n", seek_pos);
1131 AVFormatContext *format_ctx = anim->pFormatCtx;
1136 if (!(format_ctx->iformat->flags & AVFMT_TS_DISCONT)) {
1137 ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, seek_pos, AVSEEK_FLAG_BACKWARD);
1140 ret = ffmpeg_generic_seek_workaround(anim, &seek_pos, pts_to_search);
1141 av_log(anim->pFormatCtx,
1143 "Adjusted final seek seek_pos = %" PRId64 "\n",
1147 if (
ret <= 0 && !ffmpeg_seek_buffers_need_flushing(anim, position, seek_pos)) {
1153 av_log(anim->pFormatCtx,
1156 "error while seeking to DTS = %" PRId64 " (frameno = %d, PTS = %" PRId64
1157 "): errcode = %d\n",
1165 avcodec_flush_buffers(anim->pCodecCtx);
1166 ffmpeg_double_buffer_backup_frame_clear(anim);
1170 if (anim->cur_packet->stream_index == anim->videoStream) {
1171 av_packet_unref(anim->cur_packet);
1172 anim->cur_packet->stream_index = -1;
1178static bool ffmpeg_must_decode(
MovieReader *anim,
int position)
1180 return !anim->pFrame_complete || anim->
cur_position != position;
1183static bool ffmpeg_must_seek(
MovieReader *anim,
int position)
1185 bool must_seek = position != anim->
cur_position + 1 || ffmpeg_is_first_frame_decode(anim);
1186 anim->seek_before_decode = must_seek;
1192 if (anim ==
nullptr) {
1196 av_log(anim->pFormatCtx, AV_LOG_DEBUG,
"FETCH: seek_pos=%d\n", position);
1199 int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position);
1200 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
1201 double frame_rate = av_q2d(v_st->r_frame_rate);
1202 double pts_time_base = av_q2d(v_st->time_base);
1203 int64_t start_pts = v_st->start_time;
1205 if (anim->never_seek_decode_one_frame) {
1207 if (!anim->pFrame_complete) {
1208 ffmpeg_decode_video_frame(anim);
1213 av_log(anim->pFormatCtx,
1215 "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, start_pts=%" PRId64
1222 if (ffmpeg_must_decode(anim, position)) {
1223 if (ffmpeg_must_seek(anim, position)) {
1224 ffmpeg_seek_to_key_frame(anim, position, tc_index, pts_to_search);
1227 ffmpeg_decode_video_frame_scan(anim, pts_to_search);
1232 anim->
x = anim->pCodecCtx->width;
1233 anim->
y = anim->pCodecCtx->height;
1235 const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt);
1238 if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) {
1246 const size_t pixel_size = anim->is_float ? 16 : 4;
1249 if (anim->is_float) {
1258 AVFrame *final_frame = ffmpeg_frame_by_pts_get(anim, pts_to_search);
1259 if (final_frame ==
nullptr) {
1262 final_frame = ffmpeg_double_buffer_frame_fallback_get(anim);
1267 if (final_frame !=
nullptr) {
1268 ffmpeg_postprocess(anim, final_frame, cur_frame_final);
1273 return cur_frame_final;
1278 if (anim ==
nullptr) {
1282 if (anim->pCodecCtx) {
1283 avcodec_free_context(&anim->pCodecCtx);
1284 avformat_close_input(&anim->pFormatCtx);
1285 av_packet_free(&anim->cur_packet);
1287 av_frame_free(&anim->pFrame);
1288 av_frame_free(&anim->pFrame_backup);
1289 av_frame_free(&anim->pFrameRGB);
1290 if (anim->pFrameDeinterlaced->data[0] !=
nullptr) {
1291 MEM_freeN(anim->pFrameDeinterlaced->data[0]);
1293 av_frame_free(&anim->pFrameDeinterlaced);
1294 ffmpeg_sws_release_context(anim->img_convert_ctx);
1307 if (anim ==
nullptr) {
1315 free_anim_ffmpeg(anim);
1316 if (startffmpeg(anim)) {
1327 ImBuf *ibuf =
nullptr;
1346 if (anim->pFormatCtx) {
1347 AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
1348 AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st,
nullptr);
1349 if (frame_rate.num != 0) {
1351 SNPRINTF(value,
"%g", av_q2d(frame_rate));
1368 ImBuf *ibuf =
nullptr;
1369 if (anim ==
nullptr) {
1399 ibuf = ffmpeg_fetchibuf(anim, position, tc);
1443 if (anim->
frs_sec > SHRT_MAX) {
1445 r_fps_num = SHRT_MAX;
#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
#define SNPRINTF(dst, format,...)
char * STRNCPY(char(&dst)[N], const char *src)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
int BLI_system_thread_count(void)
@ COLOR_ROLE_DEFAULT_BYTE
const char * IMB_colormanagement_role_colorspace_name_get(int role)
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)
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)
MovieReader * MOV_open_file(const char *filepath, int ib_flags, int streamindex, char colorspace[IM_MAX_SPACE])
double MOV_get_start_offset_seconds(const MovieReader *anim)
int MOV_get_duration_frames(MovieReader *anim, IMB_Timecode_Type tc)
bool MOV_is_initialized_and_valid(const MovieReader *anim)
void MOV_get_filename(const MovieReader *anim, char *filename, int filename_maxncpy)
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