diff options
Diffstat (limited to 'source/blender/imbuf/intern')
-rw-r--r-- | source/blender/imbuf/intern/IMB_anim.h | 1 | ||||
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 159 | ||||
-rw-r--r-- | source/blender/imbuf/intern/colormanagement.c | 6 | ||||
-rw-r--r-- | source/blender/imbuf/intern/dds/ColorBlock.h | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/indexer.c | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/metadata.c | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/moviecache.c | 16 | ||||
-rw-r--r-- | source/blender/imbuf/intern/openexr/openexr_api.cpp | 4 |
8 files changed, 115 insertions, 77 deletions
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index cfeffcca0ea..c4e2ad9da7f 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -91,6 +91,7 @@ struct anim { int duration_in_frames; int frs_sec; double frs_sec_base; + double start_offset; int x, y; /* for number */ diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 47514308ae4..dbca16ca82b 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -425,6 +425,7 @@ static int startavi(struct anim *anim) } anim->duration_in_frames = anim->avi->header->TotalFrames; + anim->start_offset = 0.0f; anim->params = NULL; anim->x = anim->avi->header->Width; @@ -597,6 +598,13 @@ static int startffmpeg(struct anim *anim) return -1; } + double video_start = 0; + double pts_time_base = av_q2d(video_stream->time_base); + + if (video_stream->start_time != AV_NOPTS_VALUE) { + video_start = video_stream->start_time * pts_time_base; + } + frame_rate = av_guess_frame_rate(pFormatCtx, video_stream, NULL); anim->duration_in_frames = 0; @@ -616,10 +624,49 @@ static int startffmpeg(struct anim *anim) } } } - /* Fall back to the container. */ + /* Fall back to manually estimating the video stream duration. + * This is because the video stream duration can be shorter than the pFormatCtx->duration. + */ if (anim->duration_in_frames == 0) { - anim->duration_in_frames = (int)(pFormatCtx->duration * av_q2d(frame_rate) / AV_TIME_BASE + - 0.5f); + double stream_dur; + + if (video_stream->duration != AV_NOPTS_VALUE) { + stream_dur = video_stream->duration * pts_time_base; + } + else { + double audio_start = 0; + + /* Find audio stream to guess the duration of the video. + * Sometimes the audio AND the video stream have a start offset. + * The difference between these is the offset we want to use to + * calculate the video duration. + */ + for (i = 0; i < pFormatCtx->nb_streams; i++) { + if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + AVStream *audio_stream = pFormatCtx->streams[i]; + if (audio_stream->start_time != AV_NOPTS_VALUE) { + audio_start = audio_stream->start_time * av_q2d(audio_stream->time_base); + } + break; + } + } + + if (video_start > audio_start) { + stream_dur = (double)pFormatCtx->duration / AV_TIME_BASE - (video_start - audio_start); + } + else { + /* The video stream starts before or at the same time as the audio stream! + * We have to assume that the video stream is as long as the full pFormatCtx->duration. + */ + stream_dur = (double)pFormatCtx->duration / AV_TIME_BASE; + } + } + anim->duration_in_frames = (int)(stream_dur * av_q2d(frame_rate) + 0.5f); + } + + double ctx_start = 0; + if (pFormatCtx->start_time != AV_NOPTS_VALUE) { + ctx_start = (double)pFormatCtx->start_time / AV_TIME_BASE; } frs_num = frame_rate.num; @@ -634,6 +681,9 @@ static int startffmpeg(struct anim *anim) anim->frs_sec = frs_num; anim->frs_sec_base = frs_den; + /* Save the relative start time for the video. IE the start time in relation to where playback + * starts. */ + anim->start_offset = video_start - ctx_start; anim->params = 0; @@ -1019,33 +1069,21 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx) return false; } -static int64_t ffmpeg_get_seek_pos(struct anim *anim, int position) +static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search) { AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); - int64_t st_time = anim->pFormatCtx->start_time; - int64_t pos = (int64_t)(position)*AV_TIME_BASE; - /* Step back half a time base position to make sure that we get the requested - * frame and not the one after it. + AVRational frame_rate = v_st->r_frame_rate; + AVRational time_base = v_st->time_base; + double steps_per_frame = (double)(frame_rate.den * time_base.den) / + (double)(frame_rate.num * time_base.num); + /* Step back half a frame position to make sure that we get the requested + * frame and not the one after it. This is a workaround as ffmpeg will + * sometimes not seek to a frame after the requested pts even if + * AVSEEK_FLAG_BACKWARD is specified. */ - pos -= (AV_TIME_BASE / 2); - pos /= frame_rate; - - av_log(anim->pFormatCtx, - AV_LOG_DEBUG, - "NO INDEX seek pos = %" PRId64 ", st_time = %" PRId64 "\n", - pos, - (st_time != AV_NOPTS_VALUE) ? st_time : 0); - - if (pos < 0) { - pos = 0; - } - - if (st_time != AV_NOPTS_VALUE) { - pos += st_time; - } + int64_t pts = pts_to_search - (steps_per_frame / 2); - return pos; + return pts; } /* This gives us an estimate of which pts our requested frame will have. @@ -1062,17 +1100,18 @@ static int64_t ffmpeg_get_pts_to_search(struct anim *anim, pts_to_search = IMB_indexer_get_pts(tc_index, new_frame_index); } else { - int64_t st_time = anim->pFormatCtx->start_time; AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL); + int64_t start_pts = v_st->start_time; + AVRational frame_rate = v_st->r_frame_rate; AVRational time_base = v_st->time_base; - int64_t steps_per_frame = (frame_rate.den * time_base.den) / (frame_rate.num * time_base.num); - pts_to_search = position * steps_per_frame; + double steps_per_frame = (double)(frame_rate.den * time_base.den) / + (double)(frame_rate.num * time_base.num); - if (st_time != AV_NOPTS_VALUE && st_time != 0) { - int64_t start_frame = (double)st_time / AV_TIME_BASE * av_q2d(frame_rate); - pts_to_search += start_frame * steps_per_frame; + pts_to_search = round(position * steps_per_frame); + + if (start_pts != AV_NOPTS_VALUE) { + pts_to_search += start_pts; } } return pts_to_search; @@ -1156,23 +1195,29 @@ static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_sea * decoded will be read. See https://trac.ffmpeg.org/ticket/1607 and * https://developer.blender.org/T86944. */ static int ffmpeg_generic_seek_workaround(struct anim *anim, - int64_t *requested_pos, + int64_t *requested_pts, int64_t pts_to_search) { AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); - int64_t current_pos = *requested_pos; + AVRational frame_rate = v_st->r_frame_rate; + AVRational time_base = v_st->time_base; + + double steps_per_frame = (double)(frame_rate.den * time_base.den) / + (double)(frame_rate.num * time_base.num); + + int64_t current_pts = *requested_pts; int64_t offset = 0; int64_t cur_pts, prev_pts = -1; /* Step backward frame by frame until we find the key frame we are looking for. */ - while (current_pos != 0) { - current_pos = *requested_pos - ((int64_t)(offset)*AV_TIME_BASE / frame_rate); - current_pos = max_ii(current_pos, 0); + while (current_pts != 0) { + current_pts = *requested_pts - (int64_t)round(offset * steps_per_frame); + current_pts = MAX2(current_pts, 0); /* Seek to timestamp. */ - if (av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD) < 0) { + if (av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD) < + 0) { break; } @@ -1198,21 +1243,22 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, /* We found the I-frame we were looking for! */ break; } - if (cur_pts == prev_pts) { - /* We got the same key frame packet twice. - * This probably means that we have hit the beginning of the stream. */ - break; - } + } + + if (cur_pts == prev_pts) { + /* We got the same key frame packet twice. + * This probably means that we have hit the beginning of the stream. */ + break; } prev_pts = cur_pts; offset++; } - *requested_pos = current_pos; + *requested_pts = current_pts; /* Re-seek to timestamp that gave I-frame, so it can be read by decode function. */ - return av_seek_frame(anim->pFormatCtx, -1, current_pos, AVSEEK_FLAG_BACKWARD); + return av_seek_frame(anim->pFormatCtx, anim->videoStream, current_pts, AVSEEK_FLAG_BACKWARD); } /* Seek to last necessary key frame. */ @@ -1260,13 +1306,13 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, else { /* We have to manually seek with ffmpeg to get to the key frame we want to start decoding from. */ - pos = ffmpeg_get_seek_pos(anim, position); + pos = ffmpeg_get_seek_pts(anim, pts_to_search); av_log(anim->pFormatCtx, AV_LOG_DEBUG, "NO INDEX final seek pos = %" PRId64 "\n", pos); AVFormatContext *format_ctx = anim->pFormatCtx; if (format_ctx->iformat->read_seek2 || format_ctx->iformat->read_seek) { - ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); + ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, pos, AVSEEK_FLAG_BACKWARD); } else { ret = ffmpeg_generic_seek_workaround(anim, &pos, pts_to_search); @@ -1311,7 +1357,7 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim, anim->cur_key_frame_pts = gop_pts; /* Seek back so we are at the correct position after we decoded a frame. */ - av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); + av_seek_frame(anim->pFormatCtx, anim->videoStream, pos, AVSEEK_FLAG_BACKWARD); } } @@ -1351,18 +1397,18 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ struct anim_index *tc_index = IMB_anim_open_index(anim, tc); int64_t pts_to_search = ffmpeg_get_pts_to_search(anim, tc_index, position); AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - double frame_rate = av_q2d(av_guess_frame_rate(anim->pFormatCtx, v_st, NULL)); + double frame_rate = av_q2d(v_st->r_frame_rate); double pts_time_base = av_q2d(v_st->time_base); - int64_t st_time = anim->pFormatCtx->start_time; + int64_t start_pts = v_st->start_time; av_log(anim->pFormatCtx, AV_LOG_DEBUG, - "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, st_time=%" PRId64 + "FETCH: looking for PTS=%" PRId64 " (pts_timebase=%g, frame_rate=%g, start_pts=%" PRId64 ")\n", (int64_t)pts_to_search, pts_time_base, frame_rate, - st_time); + start_pts); if (ffmpeg_pts_matches_last_frame(anim, pts_to_search)) { av_log(anim->pFormatCtx, @@ -1637,6 +1683,11 @@ int IMB_anim_get_duration(struct anim *anim, IMB_Timecode_Type tc) return IMB_indexer_get_duration(idx); } +double IMD_anim_get_offset(struct anim *anim) +{ + return anim->start_offset; +} + bool IMB_anim_get_fps(struct anim *anim, short *frs_sec, float *frs_sec_base, bool no_av_base) { double frs_sec_base_double; diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 2cc44ebc67b..8b2ac2ed22d 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -759,11 +759,7 @@ static bool colormanage_use_look(const char *look, const char *view_name) void colormanage_cache_free(ImBuf *ibuf) { - if (ibuf->display_buffer_flags) { - MEM_freeN(ibuf->display_buffer_flags); - - ibuf->display_buffer_flags = NULL; - } + MEM_SAFE_FREE(ibuf->display_buffer_flags); if (ibuf->colormanage_cache) { ColormanageCacheData *cache_data = colormanage_cachedata_get(ibuf); diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h index 158695cfbf3..934837bb129 100644 --- a/source/blender/imbuf/intern/dds/ColorBlock.h +++ b/source/blender/imbuf/intern/dds/ColorBlock.h @@ -25,7 +25,7 @@ * Original license from NVIDIA follows. */ -// This code is in the public domain -- <castanyo@yahoo.es> +/* This code is in the public domain -- <castanyo@yahoo.es> */ #pragma once diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 27195b294d6..bbb0f3b5b22 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -1022,7 +1022,7 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context, stream_size = avio_size(context->iFormatCtx->pb); - context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL)); + context->frame_rate = av_q2d(context->iStream->r_frame_rate); context->pts_time_base = av_q2d(context->iStream->time_base); while (av_read_frame(context->iFormatCtx, next_packet) >= 0) { diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c index c59997b34f5..5a01c42cf00 100644 --- a/source/blender/imbuf/intern/metadata.c +++ b/source/blender/imbuf/intern/metadata.c @@ -44,7 +44,7 @@ void IMB_metadata_ensure(struct IDProperty **metadata) return; } - IDPropertyTemplate val; + IDPropertyTemplate val = {0}; *metadata = IDP_New(IDP_GROUP, &val, "metadata"); } diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index e395222a214..6cc1932eff6 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -179,10 +179,7 @@ static void IMB_moviecache_destructor(void *p) item->c_handle = NULL; /* force cached segments to be updated */ - if (cache->points) { - MEM_freeN(cache->points); - cache->points = NULL; - } + MEM_SAFE_FREE(cache->points); } } @@ -355,10 +352,7 @@ static void do_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf, boo /* cache limiter can't remove unused keys which points to destroyed values */ check_unused_keys(cache); - if (cache->points) { - MEM_freeN(cache->points); - cache->points = NULL; - } + MEM_SAFE_FREE(cache->points); } void IMB_moviecache_put(MovieCache *cache, void *userkey, ImBuf *ibuf) @@ -488,11 +482,7 @@ void IMB_moviecache_get_cache_segments( } if (cache->proxy != proxy || cache->render_flags != render_flags) { - if (cache->points) { - MEM_freeN(cache->points); - } - - cache->points = NULL; + MEM_SAFE_FREE(cache->points); } if (cache->points) { diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index d1fa26e1a3e..cd323e72003 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -69,7 +69,7 @@ extern "C" { -// The following prevents a linking error in debug mode for MSVC using the libs in CVS +/* The following prevents a linking error in debug mode for MSVC using the libs in SVN. */ #if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && _MSC_VER < 1900 _CRTIMP void __cdecl _invalid_parameter_noinfo(void) { @@ -1711,7 +1711,7 @@ static const char *exr_rgba_channelname(MultiPartInputFile &file, const char *ch const ChannelList &channels = file.header(0).channels(); for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) { - /* const Channel &channel = i.channel(); */ /* Not used yet */ + // const Channel &channel = i.channel(); /* Not used yet. */ const char *str = i.name(); int len = strlen(str); if (len) { |