diff --git a/src/Makefile.am b/src/Makefile.am index edb95adb..5b857817 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,6 +18,8 @@ stream_core_files = \ stream/stream_proto.h \ stream/stream_media.h \ stream/stream_media.c \ + stream/stream_media_buffer.h \ + stream/stream_media_buffer.c \ stream/stream_playback_clock.h \ stream/stream_playback_clock.c \ stream/stream_block.h \ diff --git a/src/stream/stream_media_buffer.c b/src/stream/stream_media_buffer.c index bafed38c..14d2e477 100644 --- a/src/stream/stream_media_buffer.c +++ b/src/stream/stream_media_buffer.c @@ -3,6 +3,7 @@ #include "../../lib/debug_config.h" #include "../../lib/mem.h" +#include "../../lib/u_async.h" #include "stream_media_buffer.h" struct media_position { @@ -35,6 +36,7 @@ struct stream_media_cursor { uint8_t *scratch[2], *frame; size_t scratch_capacity, frame_capacity; uint64_t scratch_seq[2]; + size_t scratch_length[2]; int scratch_valid[2]; unsigned scratch_next; uint8_t opus[STREAM_MEDIA_MAX_OPUS]; @@ -163,6 +165,11 @@ int stream_media_store_feed(struct stream_media_store *s, uint64_t seq, const ui for (unsigned i = 0; i < b.video_count; i++) { const struct stream_media_video *v = &b.video[i]; if (!v->offset) { + if (s->video_us >= 0 && ((int64_t)v->pts_us <= s->video_us || v->frame_id <= s->last_frame_id)) { + DEBUG_WARN(DEBUG_CATEGORY_STREAM, "media index stale video seq=%llu frame=%llu pts=%llu", + (unsigned long long)seq, (unsigned long long)v->frame_id, (unsigned long long)v->pts_us); + continue; + } if (s->pending_used) { DEBUG_WARN(DEBUG_CATEGORY_STREAM, "media index incomplete frame=%llu before frame=%llu; require KEY", (unsigned long long)s->pending.frame_id, (unsigned long long)v->frame_id); @@ -281,16 +288,9 @@ static int cursor_block(struct stream_media_cursor *c, uint64_t seq, struct stre slot = c->scratch_next++ % 2; int result = stream_buffer_decode(s->buffer, seq, c->scratch[slot], c->scratch_capacity, &length); if (result != STREAM_OK) return result == STREAM_REJECTED ? STREAM_GAP : result; - c->scratch_seq[slot] = seq; c->scratch_valid[slot] = 1; + c->scratch_seq[slot] = seq; c->scratch_length[slot] = length; c->scratch_valid[slot] = 1; } else { - /* length сохраняется в первом поле зарезервированного хвоста не нужна: длину даёт metadata RS. */ - const uint8_t *wire; uint64_t actual; size_t wire_length; - int found = STREAM_GAP; - for (unsigned sub = 0; sub < s->descriptor.n; sub++) { - found = stream_buffer_read(s->buffer, seq, (uint8_t)sub, &wire, &wire_length, &actual); - if (found == STREAM_OK) { length = (size_t)stream_read_be(wire + STREAM_BLOCK_LENGTH_OFF, 4); break; } - } - if (found != STREAM_OK) return found; + length = c->scratch_length[slot]; } return stream_media_parse(c->scratch[slot], length, block); } @@ -323,6 +323,8 @@ 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 + && (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 (v->frame_size > c->frame_capacity) { @@ -370,7 +372,7 @@ int stream_media_cursor_read(struct stream_media_cursor *c, int64_t position, in if (c->audio.ended && c->video.ended) { *packet = (struct stream_media_packet){.kind = STREAM_MEDIA_READ_END}; return STREAM_OK; } - int64_t limit = position < 0 ? c->start_us : position + lookahead; + int64_t limit = position < 0 ? c->start_us : position > INT64_MAX - lookahead ? INT64_MAX : position + lookahead; if (ar == STREAM_OK && audio_pts <= limit && (audio_pts < video_pts || vr != STREAM_OK)) { /* video peek мог переиспользовать scratch аудио: заново взять ту же пачку из двухэлементного cache. */ result = cursor_block(c, c->audio.seq, &audio);