Gate media cursor revision changes on a complete keyframe

This commit is contained in:
evgeny committed 2026-10-14 16:22:15 +02:00
1 parent afa8fd307a
commit d209ab94ba
2 files changed
+101 -17

No files matched your search

+21 -7
View File
@@ -30,8 +30,8 @@ struct cursor_track { uint64_t seq; unsigned entry; int ended; };
struct stream_media_cursor {
struct stream_media_store *store;
struct cursor_track video, audio;
uint32_t generation;
int initialized, key_delivered;
uint32_t generation, video_revision;
int initialized;
unsigned tracks;
int64_t start_us;
uint8_t *scratch[2], *frame;
@@ -257,7 +257,8 @@ void stream_media_cursor_destroy(struct stream_media_cursor *c) {
void stream_media_cursor_reset(struct stream_media_cursor *c) {
if (!c) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media cursor reset: null cursor"); return; }
c->initialized = c->key_delivered = 0; c->pending_used = 0;
c->initialized = 0; c->video_revision = 0; c->pending_used = 0;
c->pending = (struct stream_media_video){0}; c->pending_format = (struct stream_media_format){0};
c->scratch_valid[0] = c->scratch_valid[1] = 0;
c->video = (struct cursor_track){0}; c->audio = (struct cursor_track){0};
c->audio.ended = !(c->tracks & STREAM_MEDIA_TRACK_AUDIO);
@@ -358,10 +359,19 @@ static int cursor_video(struct stream_media_cursor *c, struct stream_media_packe
int result = cursor_peek(c, &c->video, 1, &b, &pts);
if (result != STREAM_OK) return result;
const struct stream_media_video *v = &b.video[c->video.entry++];
if (!c->key_delivered && !c->pending.frame_size
if (b.format.revision != c->pending_format.revision) {
DEBUG_DEBUG(DEBUG_CATEGORY_STREAM, "media cursor revision source=%llx seq=%llu revision=%u->%u pending=%u; require KEY",
(unsigned long long)c->store->descriptor.source_node_id, (unsigned long long)c->video.seq,
c->pending_format.revision, b.format.revision, c->pending_used);
c->pending = (struct stream_media_video){0}; c->pending_used = 0; c->pending_format = b.format;
}
/* Revision относится к уже выданному видео этого reader, а не к текущему live store. */
if (b.format.revision != c->video_revision && !(v->flags & STREAM_MEDIA_KEY)) continue;
if (!c->pending.frame_size && v->offset) continue;
if (!c->video_revision && !c->pending.frame_size
&& (v->offset || !(v->flags & STREAM_MEDIA_KEY) || pts != c->start_us)) continue;
if (!v->offset) {
if (!c->key_delivered && (!(v->flags & STREAM_MEDIA_KEY) || pts != c->start_us)) continue;
if (!c->video_revision && (!(v->flags & STREAM_MEDIA_KEY) || pts != c->start_us)) continue;
if (v->frame_size > c->frame_capacity) {
uint8_t *frame = u_realloc(c->frame, v->frame_size);
if (!frame) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media cursor frame allocation failed bytes=%u", v->frame_size); return STREAM_ERR_MEMORY; }
@@ -370,7 +380,7 @@ static int cursor_video(struct stream_media_cursor *c, struct stream_media_packe
c->pending = *v; c->pending.data = NULL; c->pending_used = 0; c->pending_format = b.format;
}
if (!c->pending.frame_size || v->frame_id != c->pending.frame_id || v->offset != c->pending_used
|| v->pts_us != c->pending.pts_us || v->frame_size != c->pending.frame_size) {
|| v->pts_us != c->pending.pts_us || v->frame_size != c->pending.frame_size || v->flags != c->pending.flags) {
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "media cursor fragment conflict seq=%llu frame=%llu offset=%u used=%u",
(unsigned long long)c->video.seq, (unsigned long long)v->frame_id, v->offset, c->pending_used);
return STREAM_GAP;
@@ -379,7 +389,11 @@ static int cursor_video(struct stream_media_cursor *c, struct stream_media_packe
if (c->pending_used != c->pending.frame_size) continue;
struct stream_media_packet out = {.kind = STREAM_MEDIA_READ_VIDEO, .format = c->pending_format, .video = c->pending};
out.video.offset = 0; out.video.length = out.video.frame_size; out.video.data = c->frame;
c->pending_used = 0; c->pending.frame_size = 0; c->key_delivered = 1; *packet = out;
if (c->video_revision != b.format.revision) DEBUG_INFO(DEBUG_CATEGORY_STREAM,
"media cursor KEY ready source=%llx revision=%u frame=%llu pts=%llu bytes=%u",
(unsigned long long)c->store->descriptor.source_node_id, b.format.revision,
(unsigned long long)v->frame_id, (unsigned long long)v->pts_us, v->frame_size);
c->pending_used = 0; c->pending.frame_size = 0; c->video_revision = b.format.revision; *packet = out;
return STREAM_OK;
}
return STREAM_MORE;