From 60afb46c8d4c3db6bb4d82bf00bc8741fa390713 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 11 Nov 2018 15:27:52 +0100 Subject: [PATCH] Store queue of PTS for pending frames Several frames may be read by read_packet() before they are consumed (returned by av_read_frame()), so we need to store the PTS of frames in order, so that the right PTS is assigned to the right frame. --- app/src/decoder.c | 59 ++++++++++++++++++++++++++++++++++++++++++----- app/src/decoder.h | 9 ++++++-- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index 4fbc12bf..bc164210 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -20,6 +20,46 @@ #define HEADER_SIZE 12 +static struct frame_meta *frame_meta_new(uint64_t pts) { + struct frame_meta *meta = malloc(sizeof(*meta)); + if (!meta) { + return meta; + } + meta->pts = pts; + meta->next = NULL; + return meta; +} + +static void frame_meta_delete(struct frame_meta *frame_meta) { + free(frame_meta); +} + +static SDL_bool receiver_state_push_meta(struct receiver_state *state, + uint64_t pts) { + struct frame_meta *frame_meta = frame_meta_new(pts); + if (!frame_meta) { + return SDL_FALSE; + } + + // append to the list + // (iterate to find the last item, in practice the list should be tiny) + struct frame_meta **p = &state->frame_meta_queue; + while (*p) { + p = &(*p)->next; + } + *p = frame_meta; + return SDL_TRUE; +} + +static uint64_t receiver_state_take_meta(struct receiver_state *state) { + struct frame_meta *frame_meta = state->frame_meta_queue; // first item + SDL_assert(frame_meta); // must not be empty + uint64_t pts = frame_meta->pts; + state->frame_meta_queue = frame_meta->next; // remove the item + frame_meta_delete(frame_meta); + return pts; +} + static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { struct decoder *decoder = opaque; struct receiver_state *state = &decoder->receiver_state; @@ -37,9 +77,6 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { // It is followed by bytes containing the packet/frame. if (!state->remaining) { - // the next PTS is now for the current frame - state->pts = state->next_pts; - #define HEADER_SIZE 12 uint8_t header[HEADER_SIZE]; ssize_t ret = net_recv_all(decoder->video_socket, header, HEADER_SIZE); @@ -49,8 +86,14 @@ static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) { // no partial read (net_recv_all()) SDL_assert_release(ret == HEADER_SIZE); - state->next_pts = buffer_read64be(header); + uint64_t pts = buffer_read64be(header); state->remaining = buffer_read32be(&header[8]); + + if (!receiver_state_push_meta(state, pts)) { + LOGE("Could not store PTS for recording"); + // we cannot save the PTS, the recording would be broken + return -1; + } } SDL_assert(state->remaining); @@ -126,6 +169,7 @@ static int run_decoder(void *data) { } // initialize the receiver state + decoder->receiver_state.frame_meta_queue = NULL; decoder->receiver_state.remaining = 0; // if recording is enabled, a "header" is sent between raw packets @@ -195,8 +239,11 @@ static int run_decoder(void *data) { #endif if (decoder->recorder) { - packet.pts = decoder->receiver_state.pts; - packet.dts = decoder->receiver_state.pts; + // we retrieve the PTS in order they were received, so they will + // be assigned to the correct frame + uint64_t pts = receiver_state_take_meta(&decoder->receiver_state); + packet.pts = pts; + packet.dts = pts; // no need to rescale with av_packet_rescale_ts(), the timestamps // are in microseconds both in input and output diff --git a/app/src/decoder.h b/app/src/decoder.h index 2aeb1824..610de000 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -9,6 +9,11 @@ struct frames; +struct frame_meta { + uint64_t pts; + struct frame_meta *next; +}; + struct decoder { struct frames *frames; socket_t video_socket; @@ -16,8 +21,8 @@ struct decoder { SDL_mutex *mutex; struct recorder *recorder; struct receiver_state { - uint64_t next_pts; - uint64_t pts; + // meta (in order) for frames not consumed yet + struct frame_meta *frame_meta_queue; size_t remaining; // remaining bytes to receive for the current frame } receiver_state; };