VSE: Remove byte position index from our time codes

This is a more invasive change to the timecode indexer because ffmpeg removed the ability to to get the `pkt_pos` (byte location of a frame packet):
https://github.com/FFmpeg/FFmpeg/commit/27f8c9b27bce42a4a6a4c64e03fab769579c8683
As stated there, they don't think that using it too seek is any better than using the dts or the pts position of the packets.
While you can still seek with the byte position, you need to do quite a bit of extra work to get this information from ffmpeg.
As we are only using it for the indexer and only if the fileformat was quite old (mpegts etc) I thought that we could instead simplify this and always seek by the pts timestamp instead.

Pull Request: https://projects.blender.org/blender/blender/pulls/130444
This commit is contained in:
Sebastian Parborg
2024-11-18 17:46:33 +01:00
committed by Sebastian Parborg
parent b1ca2f09db
commit 4acb7455df
3 changed files with 16 additions and 109 deletions
+1 -7
View File
@@ -36,7 +36,6 @@
struct anim_index_entry {
int frameno;
uint64_t seek_pos;
uint64_t seek_pos_pts;
uint64_t seek_pos_dts;
uint64_t pts;
@@ -68,7 +67,6 @@ struct anim_index_builder {
anim_index_builder *IMB_index_builder_create(const char *filepath);
void IMB_index_builder_add_entry(anim_index_builder *fp,
int frameno,
uint64_t seek_pos,
uint64_t seek_pos_pts,
uint64_t seek_pos_dts,
uint64_t pts);
@@ -77,15 +75,13 @@ void IMB_index_builder_proc_frame(anim_index_builder *fp,
unsigned char *buffer,
int data_size,
int frameno,
uint64_t seek_pos,
uint64_t seek_pos_pts,
uint64_t seek_pos_dts,
uint64_t pts);
void IMB_index_builder_finish(anim_index_builder *fp, int rollback);
ImBufAnimIndex *IMB_indexer_open(const char *name);
uint64_t IMB_indexer_get_seek_pos(ImBufAnimIndex *idx, int frame_index);
ImBufAnimIndex *IMB_indexer_open(const char *filepath);
uint64_t IMB_indexer_get_seek_pos_pts(ImBufAnimIndex *idx, int frame_index);
uint64_t IMB_indexer_get_seek_pos_dts(ImBufAnimIndex *idx, int frame_index);
@@ -93,8 +89,6 @@ int IMB_indexer_get_frame_index(ImBufAnimIndex *idx, int frameno);
uint64_t IMB_indexer_get_pts(ImBufAnimIndex *idx, int frame_index);
int IMB_indexer_get_duration(ImBufAnimIndex *idx);
int IMB_indexer_can_scan(ImBufAnimIndex *idx, int old_frame_index, int new_frame_index);
void IMB_indexer_close(ImBufAnimIndex *idx);
void IMB_free_indices(ImBufAnim *anim);
+4 -64
View File
@@ -805,48 +805,6 @@ static int ffmpeg_decode_video_frame(ImBufAnim *anim)
return (rval >= 0);
}
static int match_format(const char *name, AVFormatContext *pFormatCtx)
{
const char *p;
int len, namelen;
const char *names = pFormatCtx->iformat->name;
if (!name || !names) {
return 0;
}
namelen = strlen(name);
while ((p = strchr(names, ','))) {
len = std::max(int(p - names), namelen);
if (!BLI_strncasecmp(name, names, len)) {
return 1;
}
names = p + 1;
}
return !BLI_strcasecmp(name, names);
}
static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
{
static const char *byte_seek_list[] = {"mpegts", nullptr};
const char **p;
if (pFormatCtx->iformat->flags & AVFMT_TS_DISCONT) {
return true;
}
p = byte_seek_list;
while (*p) {
if (match_format(*p++, pFormatCtx)) {
return true;
}
}
return false;
}
static int64_t ffmpeg_get_seek_pts(ImBufAnim *anim, int64_t pts_to_search)
{
/* FFMPEG seeks internally using DTS values instead of PTS. In some files DTS and PTS values are
@@ -1048,35 +1006,17 @@ static int ffmpeg_seek_to_key_frame(ImBufAnim *anim,
if (tc_index) {
/* We can use timestamps generated from our indexer to seek. */
int new_frame_index = IMB_indexer_get_frame_index(tc_index, position);
int old_frame_index = IMB_indexer_get_frame_index(tc_index, anim->cur_position);
if (IMB_indexer_can_scan(tc_index, old_frame_index, new_frame_index)) {
/* No need to seek, return early. */
return 0;
}
uint64_t pts;
uint64_t dts;
seek_pos = IMB_indexer_get_seek_pos(tc_index, new_frame_index);
pts = IMB_indexer_get_seek_pos_pts(tc_index, new_frame_index);
dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index);
uint64_t pts = IMB_indexer_get_seek_pos_pts(tc_index, new_frame_index);
uint64_t dts = IMB_indexer_get_seek_pos_dts(tc_index, new_frame_index);
anim->cur_key_frame_pts = timestamp_from_pts_or_dts(pts, dts);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek seek_pos = %" PRId64 "\n", seek_pos);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek pts = %" PRIu64 "\n", pts);
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "TC INDEX seek dts = %" PRIu64 "\n", dts);
if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using BYTE seek_pos\n");
ret = av_seek_frame(anim->pFormatCtx, -1, seek_pos, AVSEEK_FLAG_BYTE);
}
else {
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "... using PTS seek_pos\n");
ret = av_seek_frame(
anim->pFormatCtx, anim->videoStream, anim->cur_key_frame_pts, AVSEEK_FLAG_BACKWARD);
}
av_log(anim->pFormatCtx, AV_LOG_DEBUG, "Using PTS from timecode as seek_pos\n");
ret = av_seek_frame(anim->pFormatCtx, anim->videoStream, pts, AVSEEK_FLAG_BACKWARD);
}
else {
/* We have to manually seek with ffmpeg to get to the key frame we want to start decoding from.
+11 -38
View File
@@ -7,6 +7,11 @@
*/
#include <cstdlib>
#ifndef WIN32
# include <unistd.h>
#else
# include <io.h>
#endif
#include "MEM_guardedalloc.h"
@@ -32,7 +37,6 @@
#include "IMB_anim.hh"
#include "IMB_imbuf.hh"
#include "IMB_indexer.hh"
#include "imbuf.hh"
#ifdef WITH_FFMPEG
extern "C" {
@@ -90,13 +94,13 @@ anim_index_builder *IMB_index_builder_create(const char *filepath)
void IMB_index_builder_add_entry(anim_index_builder *fp,
int frameno,
uint64_t seek_pos,
uint64_t seek_pos_pts,
uint64_t seek_pos_dts,
uint64_t pts)
{
uint64_t pad = 0;
fwrite(&frameno, sizeof(int), 1, fp->fp);
fwrite(&seek_pos, sizeof(uint64_t), 1, fp->fp);
fwrite(&pad, sizeof(uint64_t), 1, fp->fp);
fwrite(&seek_pos_pts, sizeof(uint64_t), 1, fp->fp);
fwrite(&seek_pos_dts, sizeof(uint64_t), 1, fp->fp);
fwrite(&pts, sizeof(uint64_t), 1, fp->fp);
@@ -106,7 +110,6 @@ void IMB_index_builder_proc_frame(anim_index_builder *fp,
uchar *buffer,
int data_size,
int frameno,
uint64_t seek_pos,
uint64_t seek_pos_pts,
uint64_t seek_pos_dts,
uint64_t pts)
@@ -114,7 +117,6 @@ void IMB_index_builder_proc_frame(anim_index_builder *fp,
if (fp->proc_frame) {
anim_index_entry e;
e.frameno = frameno;
e.seek_pos = seek_pos;
e.seek_pos_pts = seek_pos_pts;
e.seek_pos_dts = seek_pos_dts;
e.pts = pts;
@@ -122,7 +124,7 @@ void IMB_index_builder_proc_frame(anim_index_builder *fp,
fp->proc_frame(fp, buffer, data_size, &e);
}
else {
IMB_index_builder_add_entry(fp, frameno, seek_pos, seek_pos_pts, seek_pos_dts, pts);
IMB_index_builder_add_entry(fp, frameno, seek_pos_pts, seek_pos_dts, pts);
}
}
@@ -183,7 +185,7 @@ ImBufAnimIndex *IMB_indexer_open(const char *filepath)
fseek(fp, 0, SEEK_END);
idx->num_entries = (ftell(fp) - 12) / (sizeof(int) + /* framepos */
sizeof(uint64_t) + /* seek_pos */
sizeof(uint64_t) + /* _pad */
sizeof(uint64_t) + /* seek_pos_pts */
sizeof(uint64_t) + /* seek_pos_dts */
sizeof(uint64_t) /* pts */
@@ -195,9 +197,10 @@ ImBufAnimIndex *IMB_indexer_open(const char *filepath)
MEM_callocN(sizeof(anim_index_entry) * idx->num_entries, "anim_index_entries"));
size_t items_read = 0;
uint64_t pad;
for (i = 0; i < idx->num_entries; i++) {
items_read += fread(&idx->entries[i].frameno, sizeof(int), 1, fp);
items_read += fread(&idx->entries[i].seek_pos, sizeof(uint64_t), 1, fp);
items_read += fread(&pad, sizeof(uint64_t), 1, fp);
items_read += fread(&idx->entries[i].seek_pos_pts, sizeof(uint64_t), 1, fp);
items_read += fread(&idx->entries[i].seek_pos_dts, sizeof(uint64_t), 1, fp);
items_read += fread(&idx->entries[i].pts, sizeof(uint64_t), 1, fp);
@@ -214,7 +217,6 @@ ImBufAnimIndex *IMB_indexer_open(const char *filepath)
if ((ENDIAN_ORDER == B_ENDIAN) != (header[8] == 'V')) {
for (i = 0; i < idx->num_entries; i++) {
BLI_endian_switch_int32(&idx->entries[i].frameno);
BLI_endian_switch_uint64(&idx->entries[i].seek_pos);
BLI_endian_switch_uint64(&idx->entries[i].seek_pos_pts);
BLI_endian_switch_uint64(&idx->entries[i].seek_pos_dts);
BLI_endian_switch_uint64(&idx->entries[i].pts);
@@ -226,19 +228,6 @@ ImBufAnimIndex *IMB_indexer_open(const char *filepath)
return idx;
}
uint64_t IMB_indexer_get_seek_pos(ImBufAnimIndex *idx, int frame_index)
{
/* This is hard coded, because our current timecode files return non zero seek position for index
* 0. Only when seeking to 0 it is guaranteed, that first packet will be read. */
if (frame_index <= 0) {
return 0;
}
if (frame_index >= idx->num_entries) {
frame_index = idx->num_entries - 1;
}
return idx->entries[frame_index].seek_pos;
}
uint64_t IMB_indexer_get_seek_pos_pts(ImBufAnimIndex *idx, int frame_index)
{
if (frame_index < 0) {
@@ -312,15 +301,6 @@ int IMB_indexer_get_duration(ImBufAnimIndex *idx)
return idx->entries[idx->num_entries - 1].frameno + 1;
}
int IMB_indexer_can_scan(ImBufAnimIndex *idx, int old_frame_index, int new_frame_index)
{
/* makes only sense, if it is the same I-Frame and we are not
* trying to run backwards in time... */
return (IMB_indexer_get_seek_pos(idx, old_frame_index) ==
IMB_indexer_get_seek_pos(idx, new_frame_index) &&
old_frame_index < new_frame_index);
}
void IMB_indexer_close(ImBufAnimIndex *idx)
{
MEM_freeN(idx->entries);
@@ -785,10 +765,8 @@ struct FFmpegIndexBuilderContext : public IndexBuildContext {
int tcs_in_use;
int proxy_sizes_in_use;
uint64_t seek_pos;
uint64_t seek_pos_pts;
uint64_t seek_pos_dts;
uint64_t last_seek_pos;
uint64_t last_seek_pos_pts;
uint64_t last_seek_pos_dts;
uint64_t start_pts;
@@ -955,7 +933,6 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c
AVFrame *in_frame)
{
int i;
uint64_t s_pos = context->seek_pos;
uint64_t s_pts = context->seek_pos_pts;
uint64_t s_dts = context->seek_pos_dts;
uint64_t pts = av_get_pts_from_frame(in_frame);
@@ -979,7 +956,6 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c
* before our seek I-Frame. So we need to pick the previous available
* I-Frame to be able to decode this one properly.
*/
s_pos = context->last_seek_pos;
s_pts = context->last_seek_pos_pts;
s_dts = context->last_seek_pos_dts;
}
@@ -996,7 +972,6 @@ static void index_rebuild_ffmpeg_proc_decoded_frame(FFmpegIndexBuilderContext *c
curr_packet->data,
curr_packet->size,
tc_frameno,
s_pos,
s_pts,
s_dts,
pts);
@@ -1051,11 +1026,9 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
}
if (next_packet->flags & AV_PKT_FLAG_KEY) {
context->last_seek_pos = context->seek_pos;
context->last_seek_pos_pts = context->seek_pos_pts;
context->last_seek_pos_dts = context->seek_pos_dts;
context->seek_pos = in_frame->pkt_pos;
context->seek_pos_pts = in_frame->pts;
context->seek_pos_dts = in_frame->pkt_dts;
}