VSE: Reduce playback stalls when new video clips start playing #118503
|
@ -333,7 +333,6 @@ void IMB_close_anim(ImBufAnim *anim);
|
|||
void IMB_close_anim_proxies(ImBufAnim *anim);
|
||||
bool IMB_anim_can_produce_frames(const ImBufAnim *anim);
|
||||
|
||||
int ismovie(const char *filepath);
|
||||
int IMB_anim_get_image_width(ImBufAnim *anim);
|
||||
int IMB_anim_get_image_height(ImBufAnim *anim);
|
||||
bool IMB_get_gop_decode_time(ImBufAnim *anim);
|
||||
|
@ -397,12 +396,12 @@ bool IMB_ispic_type_matches(const char *filepath, int filetype);
|
|||
int IMB_ispic_type_from_memory(const unsigned char *buf, size_t buf_size);
|
||||
int IMB_ispic_type(const char *filepath);
|
||||
|
||||
enum class ImbAnimType { NotAnim, Sequence, Movie, Ffmpeg };
|
||||
|
||||
/**
|
||||
* Test if the file is a video file (known format, has a video stream and
|
||||
* supported video codec).
|
||||
*/
|
||||
bool IMB_isanim(const char *filepath);
|
||||
|
||||
ImbAnimType imb_get_anim_type(const char *filepath);
|
||||
|
||||
/**
|
||||
* Test if color-space conversions of pixels in buffer need to take into account alpha.
|
||||
*/
|
||||
|
|
|
@ -8,36 +8,26 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include "imbuf.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
#include "IMB_imbuf_enums.h"
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
extern "C" {
|
||||
# include <libavcodec/avcodec.h>
|
||||
# include <libavformat/avformat.h>
|
||||
# include <libswscale/swscale.h>
|
||||
}
|
||||
struct AVFormatContext;
|
||||
struct AVCodecContext;
|
||||
struct AVCodec;
|
||||
struct AVFrame;
|
||||
struct AVPacket;
|
||||
struct SwsContext;
|
||||
#endif
|
||||
|
||||
struct IDProperty;
|
||||
struct ImBufAnimIndex;
|
||||
|
||||
struct ImBufAnim {
|
||||
enum class State { Uninitialized, Failed, Valid };
|
||||
int ib_flags;
|
||||
ImbAnimType curtype;
|
||||
State state;
|
||||
int cur_position; /* index 0 = 1e, 1 = 2e, enz. */
|
||||
int duration_in_frames;
|
||||
int frs_sec;
|
||||
|
@ -47,16 +37,7 @@ struct ImBufAnim {
|
|||
|
||||
/* for number */
|
||||
char filepath[1024];
|
||||
/* for sequence */
|
||||
char filepath_first[1024];
|
||||
|
||||
/* movie */
|
||||
void *movie;
|
||||
void *track;
|
||||
void *params;
|
||||
int orientation;
|
||||
size_t framesize;
|
||||
int interlacing;
|
||||
int streamindex;
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
|
@ -65,7 +46,7 @@ struct ImBufAnim {
|
|||
const AVCodec *pCodec;
|
||||
AVFrame *pFrameRGB;
|
||||
AVFrame *pFrameDeinterlaced;
|
||||
struct SwsContext *img_convert_ctx;
|
||||
SwsContext *img_convert_ctx;
|
||||
int videoStream;
|
||||
|
||||
AVFrame *pFrame;
|
||||
|
@ -85,11 +66,11 @@ struct ImBufAnim {
|
|||
int proxies_tried;
|
||||
int indices_tried;
|
||||
|
||||
struct ImBufAnim *proxy_anim[IMB_PROXY_MAX_SLOT];
|
||||
struct ImBufAnimIndex *curr_idx[IMB_TC_MAX_SLOT];
|
||||
ImBufAnim *proxy_anim[IMB_PROXY_MAX_SLOT];
|
||||
ImBufAnimIndex *curr_idx[IMB_TC_MAX_SLOT];
|
||||
|
||||
char colorspace[64];
|
||||
char suffix[64]; /* MAX_NAME - multiview */
|
||||
|
||||
struct IDProperty *metadata;
|
||||
IDProperty *metadata;
|
||||
};
|
||||
|
|
|
@ -52,25 +52,6 @@ extern "C" {
|
|||
|
||||
#endif /* WITH_FFMPEG */
|
||||
|
||||
int ismovie(const char * /*filepath*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* never called, just keep the linker happy */
|
||||
static int startmovie(ImBufAnim * /*anim*/)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
static ImBuf *movie_fetchibuf(ImBufAnim * /*anim*/, int /*position*/)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
static void free_anim_movie(ImBufAnim * /*anim*/)
|
||||
{
|
||||
/* pass */
|
||||
}
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
static void free_anim_ffmpeg(ImBufAnim *anim);
|
||||
#endif
|
||||
|
@ -82,8 +63,6 @@ void IMB_free_anim(ImBufAnim *anim)
|
|||
return;
|
||||
}
|
||||
|
||||
free_anim_movie(anim);
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
free_anim_ffmpeg(anim);
|
||||
#endif
|
||||
|
@ -113,34 +92,23 @@ void IMB_close_anim_proxies(ImBufAnim *anim)
|
|||
|
||||
IDProperty *IMB_anim_load_metadata(ImBufAnim *anim)
|
||||
{
|
||||
switch (anim->curtype) {
|
||||
case ImbAnimType::Ffmpeg: {
|
||||
if (anim->state == ImBufAnim::State::Valid) {
|
||||
#ifdef WITH_FFMPEG
|
||||
AVDictionaryEntry *entry = nullptr;
|
||||
BLI_assert(anim->pFormatCtx != nullptr);
|
||||
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "METADATA FETCH\n");
|
||||
|
||||
BLI_assert(anim->pFormatCtx != nullptr);
|
||||
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "METADATA FETCH\n");
|
||||
|
||||
while (true) {
|
||||
entry = av_dict_get(anim->pFormatCtx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX);
|
||||
if (entry == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Delay creation of the property group until there is actual metadata to put in there. */
|
||||
IMB_metadata_ensure(&anim->metadata);
|
||||
IMB_metadata_set_field(anim->metadata, entry->key, entry->value);
|
||||
AVDictionaryEntry *entry = nullptr;
|
||||
while (true) {
|
||||
entry = av_dict_get(anim->pFormatCtx->metadata, "", entry, AV_DICT_IGNORE_SUFFIX);
|
||||
if (entry == nullptr) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
/* Delay creation of the property group until there is actual metadata to put in there. */
|
||||
IMB_metadata_ensure(&anim->metadata);
|
||||
IMB_metadata_set_field(anim->metadata, entry->key, entry->value);
|
||||
}
|
||||
case ImbAnimType::Sequence:
|
||||
case ImbAnimType::Movie:
|
||||
/* TODO */
|
||||
break;
|
||||
case ImbAnimType::NotAnim:
|
||||
default:
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return anim->metadata;
|
||||
}
|
||||
|
@ -376,8 +344,6 @@ static int startffmpeg(ImBufAnim *anim)
|
|||
* starts. */
|
||||
anim->start_offset = video_start;
|
||||
|
||||
anim->params = nullptr;
|
||||
|
||||
anim->x = pCodecCtx->width;
|
||||
anim->y = pCodecCtx->height;
|
||||
|
||||
|
@ -386,10 +352,6 @@ static int startffmpeg(ImBufAnim *anim)
|
|||
anim->pCodec = pCodec;
|
||||
anim->videoStream = video_stream_index;
|
||||
|
||||
anim->interlacing = 0;
|
||||
anim->orientation = 0;
|
||||
anim->framesize = anim->x * anim->y * 4;
|
||||
|
||||
anim->cur_position = 0;
|
||||
anim->cur_pts = -1;
|
||||
anim->cur_key_frame_pts = -1;
|
||||
|
@ -1234,48 +1196,21 @@ static void free_anim_ffmpeg(ImBufAnim *anim)
|
|||
*/
|
||||
static bool anim_getnew(ImBufAnim *anim)
|
||||
{
|
||||
BLI_assert(anim->curtype == ImbAnimType::NotAnim);
|
||||
if (anim == nullptr) {
|
||||
/* Nothing to initialize. */
|
||||
return false;
|
||||
}
|
||||
|
||||
free_anim_movie(anim);
|
||||
BLI_assert(anim->state == ImBufAnim::State::Uninitialized);
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
free_anim_ffmpeg(anim);
|
||||
#endif
|
||||
|
||||
anim->curtype = imb_get_anim_type(anim->filepath);
|
||||
|
||||
switch (anim->curtype) {
|
||||
case ImbAnimType::Sequence: {
|
||||
ImBuf *ibuf = IMB_loadiffname(anim->filepath, anim->ib_flags, anim->colorspace);
|
||||
if (ibuf) {
|
||||
STRNCPY(anim->filepath_first, anim->filepath);
|
||||
anim->duration_in_frames = 1;
|
||||
IMB_freeImBuf(ibuf);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ImbAnimType::Movie:
|
||||
if (startmovie(anim)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
#ifdef WITH_FFMPEG
|
||||
case ImbAnimType::Ffmpeg:
|
||||
if (startffmpeg(anim)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
if (startffmpeg(anim)) {
|
||||
anim->state = ImBufAnim::State::Failed;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
anim->state = ImBufAnim::State::Valid;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1300,7 +1235,7 @@ ImBuf *IMB_anim_previewframe(ImBufAnim *anim)
|
|||
IMB_metadata_set_field(ibuf->metadata, "Thumb::Video::Frames", value);
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
if (anim->pFormatCtx && anim->curtype == ImbAnimType::Ffmpeg) {
|
||||
if (anim->pFormatCtx) {
|
||||
AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
|
||||
AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, nullptr);
|
||||
if (frame_rate.num != 0) {
|
||||
|
@ -1323,15 +1258,12 @@ ImBuf *IMB_anim_absolute(ImBufAnim *anim,
|
|||
IMB_Proxy_Size preview_size)
|
||||
{
|
||||
ImBuf *ibuf = nullptr;
|
||||
int filter_y;
|
||||
if (anim == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
filter_y = (anim->ib_flags & IB_animdeinterlace);
|
||||
|
||||
if (preview_size == IMB_PROXY_NONE) {
|
||||
if (anim->curtype == ImbAnimType::NotAnim) {
|
||||
if (anim->state == ImBufAnim::State::Uninitialized) {
|
||||
if (!anim_getnew(anim)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1354,45 +1286,16 @@ ImBuf *IMB_anim_absolute(ImBufAnim *anim,
|
|||
}
|
||||
}
|
||||
|
||||
switch (anim->curtype) {
|
||||
case ImbAnimType::Sequence: {
|
||||
constexpr size_t filepath_size = BOUNDED_ARRAY_TYPE_SIZE<decltype(anim->filepath_first)>();
|
||||
char head[filepath_size], tail[filepath_size];
|
||||
ushort digits;
|
||||
const int pic = BLI_path_sequence_decode(
|
||||
anim->filepath_first, head, sizeof(head), tail, sizeof(tail), &digits) +
|
||||
position;
|
||||
BLI_path_sequence_encode(anim->filepath, sizeof(anim->filepath), head, tail, digits, pic);
|
||||
ibuf = IMB_loadiffname(anim->filepath, IB_rect, anim->colorspace);
|
||||
if (ibuf) {
|
||||
anim->cur_position = position;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ImbAnimType::Movie:
|
||||
ibuf = movie_fetchibuf(anim, position);
|
||||
if (ibuf) {
|
||||
anim->cur_position = position;
|
||||
IMB_convert_rgba_to_abgr(ibuf);
|
||||
}
|
||||
break;
|
||||
#ifdef WITH_FFMPEG
|
||||
case ImbAnimType::Ffmpeg:
|
||||
ibuf = ffmpeg_fetchibuf(anim, position, tc);
|
||||
if (ibuf) {
|
||||
anim->cur_position = position;
|
||||
}
|
||||
filter_y = 0; /* done internally */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
if (anim->state == ImBufAnim::State::Valid) {
|
||||
ibuf = ffmpeg_fetchibuf(anim, position, tc);
|
||||
if (ibuf) {
|
||||
anim->cur_position = position;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ibuf) {
|
||||
if (filter_y) {
|
||||
IMB_filtery(ibuf);
|
||||
}
|
||||
SNPRINTF(ibuf->filepath, "%s.%04d", anim->filepath, anim->cur_position + 1);
|
||||
}
|
||||
return ibuf;
|
||||
|
|
|
@ -458,9 +458,7 @@ static void get_tc_filepath(ImBufAnim *anim, IMB_Timecode_Type tc, char *filepat
|
|||
* - common rebuilder structures
|
||||
* ---------------------------------------------------------------------- */
|
||||
|
||||
struct IndexBuildContext {
|
||||
ImbAnimType anim_type;
|
||||
};
|
||||
struct IndexBuildContext {};
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* - ffmpeg rebuilder
|
||||
|
@ -786,8 +784,7 @@ static void free_proxy_output_ffmpeg(proxy_output_ctx *ctx, int rollback)
|
|||
MEM_freeN(ctx);
|
||||
}
|
||||
|
||||
struct FFmpegIndexBuilderContext {
|
||||
int anim_type;
|
||||
struct FFmpegIndexBuilderContext : public IndexBuildContext {
|
||||
|
||||
AVFormatContext *iFormatCtx;
|
||||
AVCodecContext *iCodecCtx;
|
||||
|
@ -1248,7 +1245,6 @@ IndexBuildContext *IMB_anim_index_rebuild_context(ImBufAnim *anim,
|
|||
GSet *file_list,
|
||||
bool build_only_on_bad_performance)
|
||||
{
|
||||
IndexBuildContext *context = nullptr;
|
||||
int proxy_sizes_to_build = proxy_sizes_in_use;
|
||||
int i;
|
||||
|
||||
|
@ -1297,24 +1293,16 @@ IndexBuildContext *IMB_anim_index_rebuild_context(ImBufAnim *anim,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
switch (anim->curtype) {
|
||||
IndexBuildContext *context = nullptr;
|
||||
#ifdef WITH_FFMPEG
|
||||
case ImbAnimType::Ffmpeg:
|
||||
context = index_ffmpeg_create_context(
|
||||
anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
|
||||
break;
|
||||
if (anim->state == ImBufAnim::State::Valid) {
|
||||
context = index_ffmpeg_create_context(
|
||||
anim, tcs_in_use, proxy_sizes_to_build, quality, build_only_on_bad_performance);
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(build_only_on_bad_performance);
|
||||
UNUSED_VARS(build_only_on_bad_performance);
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (context) {
|
||||
context->anim_type = anim->curtype;
|
||||
}
|
||||
|
||||
return context;
|
||||
|
||||
UNUSED_VARS(tcs_in_use, proxy_sizes_in_use, quality);
|
||||
|
@ -1328,33 +1316,23 @@ void IMB_anim_index_rebuild(IndexBuildContext *context,
|
|||
/* NOLINTNEXTLINE: readability-non-const-parameter. */
|
||||
float *progress)
|
||||
{
|
||||
switch (context->anim_type) {
|
||||
#ifdef WITH_FFMPEG
|
||||
case ImbAnimType::Ffmpeg:
|
||||
if (indexer_need_to_build_proxy((FFmpegIndexBuilderContext *)context)) {
|
||||
index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
if (context != nullptr) {
|
||||
if (indexer_need_to_build_proxy((FFmpegIndexBuilderContext *)context)) {
|
||||
index_rebuild_ffmpeg((FFmpegIndexBuilderContext *)context, stop, do_update, progress);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
UNUSED_VARS(stop, do_update, progress);
|
||||
}
|
||||
|
||||
void IMB_anim_index_rebuild_finish(IndexBuildContext *context, const bool stop)
|
||||
{
|
||||
switch (context->anim_type) {
|
||||
#ifdef WITH_FFMPEG
|
||||
case ImbAnimType::Ffmpeg:
|
||||
index_rebuild_ffmpeg_finish((FFmpegIndexBuilderContext *)context, stop);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
if (context != nullptr) {
|
||||
index_rebuild_ffmpeg_finish((FFmpegIndexBuilderContext *)context, stop);
|
||||
}
|
||||
|
||||
#endif
|
||||
/* static defined at top of the file */
|
||||
UNUSED_VARS(stop, proxy_sizes);
|
||||
}
|
||||
|
|
|
@ -299,62 +299,19 @@ static int isffmpeg(const char *filepath)
|
|||
}
|
||||
#endif
|
||||
|
||||
ImbAnimType imb_get_anim_type(const char *filepath)
|
||||
bool IMB_isanim(const char *filepath)
|
||||
{
|
||||
BLI_stat_t st;
|
||||
|
||||
BLI_assert(!BLI_path_is_rel(filepath));
|
||||
|
||||
if (UTIL_DEBUG) {
|
||||
printf("%s: %s\n", __func__, filepath);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
# ifdef WITH_FFMPEG
|
||||
/* stat test below fails on large files > 4GB */
|
||||
#ifdef WITH_FFMPEG
|
||||
if (isffmpeg(filepath)) {
|
||||
return ImbAnimType::Ffmpeg;
|
||||
}
|
||||
# endif
|
||||
if (BLI_stat(filepath, &st) == -1) {
|
||||
return ImbAnimType::NotAnim;
|
||||
}
|
||||
if (((st.st_mode) & S_IFMT) != S_IFREG) {
|
||||
return ImbAnimType::NotAnim;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ismovie(filepath)) {
|
||||
return ImbAnimType::Movie;
|
||||
}
|
||||
#else /* !_WIN32 */
|
||||
if (BLI_stat(filepath, &st) == -1) {
|
||||
return ImbAnimType::NotAnim;
|
||||
}
|
||||
if (((st.st_mode) & S_IFMT) != S_IFREG) {
|
||||
return ImbAnimType::NotAnim;
|
||||
}
|
||||
|
||||
if (ismovie(filepath)) {
|
||||
return ImbAnimType::Movie;
|
||||
}
|
||||
# ifdef WITH_FFMPEG
|
||||
if (isffmpeg(filepath)) {
|
||||
return ImbAnimType::Ffmpeg;
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
/* Assume a single image is part of an image sequence. */
|
||||
if (IMB_ispic(filepath)) {
|
||||
return ImbAnimType::Sequence;
|
||||
}
|
||||
|
||||
return ImbAnimType::NotAnim;
|
||||
}
|
||||
|
||||
bool IMB_isanim(const char *filepath)
|
||||
{
|
||||
ImbAnimType type = imb_get_anim_type(filepath);
|
||||
return !ELEM(type, ImbAnimType::NotAnim, ImbAnimType::Sequence);
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue