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:
parent
345f8858d3
commit
60afb46c8d
2 changed files with 60 additions and 8 deletions
|
@ -20,6 +20,46 @@
|
||||||
|
|
||||||
#define HEADER_SIZE 12
|
#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) {
|
static int read_packet_with_meta(void *opaque, uint8_t *buf, int buf_size) {
|
||||||
struct decoder *decoder = opaque;
|
struct decoder *decoder = opaque;
|
||||||
struct receiver_state *state = &decoder->receiver_state;
|
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.
|
// It is followed by <packet_size> bytes containing the packet/frame.
|
||||||
|
|
||||||
if (!state->remaining) {
|
if (!state->remaining) {
|
||||||
// the next PTS is now for the current frame
|
|
||||||
state->pts = state->next_pts;
|
|
||||||
|
|
||||||
#define HEADER_SIZE 12
|
#define HEADER_SIZE 12
|
||||||
uint8_t header[HEADER_SIZE];
|
uint8_t header[HEADER_SIZE];
|
||||||
ssize_t ret = net_recv_all(decoder->video_socket, 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())
|
// no partial read (net_recv_all())
|
||||||
SDL_assert_release(ret == HEADER_SIZE);
|
SDL_assert_release(ret == HEADER_SIZE);
|
||||||
|
|
||||||
state->next_pts = buffer_read64be(header);
|
uint64_t pts = buffer_read64be(header);
|
||||||
state->remaining = buffer_read32be(&header[8]);
|
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);
|
SDL_assert(state->remaining);
|
||||||
|
@ -126,6 +169,7 @@ static int run_decoder(void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the receiver state
|
// initialize the receiver state
|
||||||
|
decoder->receiver_state.frame_meta_queue = NULL;
|
||||||
decoder->receiver_state.remaining = 0;
|
decoder->receiver_state.remaining = 0;
|
||||||
|
|
||||||
// if recording is enabled, a "header" is sent between raw packets
|
// if recording is enabled, a "header" is sent between raw packets
|
||||||
|
@ -195,8 +239,11 @@ static int run_decoder(void *data) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (decoder->recorder) {
|
if (decoder->recorder) {
|
||||||
packet.pts = decoder->receiver_state.pts;
|
// we retrieve the PTS in order they were received, so they will
|
||||||
packet.dts = decoder->receiver_state.pts;
|
// 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
|
// no need to rescale with av_packet_rescale_ts(), the timestamps
|
||||||
// are in microseconds both in input and output
|
// are in microseconds both in input and output
|
||||||
|
|
|
@ -9,6 +9,11 @@
|
||||||
|
|
||||||
struct frames;
|
struct frames;
|
||||||
|
|
||||||
|
struct frame_meta {
|
||||||
|
uint64_t pts;
|
||||||
|
struct frame_meta *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct decoder {
|
struct decoder {
|
||||||
struct frames *frames;
|
struct frames *frames;
|
||||||
socket_t video_socket;
|
socket_t video_socket;
|
||||||
|
@ -16,8 +21,8 @@ struct decoder {
|
||||||
SDL_mutex *mutex;
|
SDL_mutex *mutex;
|
||||||
struct recorder *recorder;
|
struct recorder *recorder;
|
||||||
struct receiver_state {
|
struct receiver_state {
|
||||||
uint64_t next_pts;
|
// meta (in order) for frames not consumed yet
|
||||||
uint64_t pts;
|
struct frame_meta *frame_meta_queue;
|
||||||
size_t remaining; // remaining bytes to receive for the current frame
|
size_t remaining; // remaining bytes to receive for the current frame
|
||||||
} receiver_state;
|
} receiver_state;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue