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.
This commit is contained in:
Romain Vimont 2018-11-11 15:27:52 +01:00
parent 345f8858d3
commit 60afb46c8d
2 changed files with 60 additions and 8 deletions

View file

@ -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 <packet_size> 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

View file

@ -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;
};