From 42ec499b673ef9cb41a5b73fce2c4effafa4a36c Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Wed, 15 May 2013 12:33:54 +0200 Subject: [PATCH] Pbuf: deletion delay only for inter-frame compress --- Makefile.in | 1 + src/host.c | 1 + src/main.c | 16 ++++++++-- src/rtp/decoders.c | 12 ++++++-- src/rtp/pbuf.c | 19 ++++++++---- src/rtp/pbuf.h | 16 ++++++++-- src/utils/list.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++ src/utils/list.h | 20 +++++++++++++ src/video_codec.c | 52 +++++++++++++++++++------------- src/video_codec.h | 2 ++ 10 files changed, 180 insertions(+), 33 deletions(-) create mode 100644 src/utils/list.c create mode 100644 src/utils/list.h diff --git a/Makefile.in b/Makefile.in index de7c6ed3c..039abc082 100644 --- a/Makefile.in +++ b/Makefile.in @@ -89,6 +89,7 @@ OBJS = @OBJS@ \ src/crypto/random.o \ src/ihdtv/ihdtv.o \ src/utils/fs_lock.o \ + src/utils/list.o \ src/utils/packet_counter.o \ src/utils/resource_manager.o \ src/utils/ring_buffer.o \ diff --git a/src/host.c b/src/host.c index b7792d88b..dcc276afc 100644 --- a/src/host.c +++ b/src/host.c @@ -130,6 +130,7 @@ void destroy_decoder(struct vcodec_state *video_decoder_state) { return; } + simple_linked_list_destroy(video_decoder_state->messages); decoder_destroy_extrn(video_decoder_state->decoder); free(video_decoder_state); diff --git a/src/main.c b/src/main.c index 6da9a97c1..038ac7c8f 100644 --- a/src/main.c +++ b/src/main.c @@ -492,6 +492,7 @@ static struct vcodec_state *new_decoder(struct state_uv *uv) { struct vcodec_state *state = calloc(1, sizeof(struct vcodec_state)); if(state) { + state->messages = simple_linked_list_init(); state->decoder = decoder_init(uv->decoder_mode, uv->postprocess, uv->display_device); if(!state->decoder) { @@ -653,10 +654,19 @@ static void *receiver_thread(void *arg) last_buf_size = new_size; } - if(cp->video_decoder_state->set_fps) { + while(simple_linked_list_size(cp->video_decoder_state->messages) > 0) { + struct vcodec_message *msg = + simple_linked_list_pop(cp->video_decoder_state->messages); + + assert(msg->type == FPS_CHANGED); + struct fps_changed_message *data = msg->data; + pbuf_set_playout_delay(cp->playout_buffer, - 1.0 / cp->video_decoder_state->set_fps); - cp->video_decoder_state->set_fps = 0.0; + 1.0 / data->val, + 1.0 / data->val * (data->interframe_codec ? 2 : 1) + ); + free(data); + free(msg); } diff --git a/src/rtp/decoders.c b/src/rtp/decoders.c index 5c064d079..f27b4b1cd 100644 --- a/src/rtp/decoders.c +++ b/src/rtp/decoders.c @@ -168,6 +168,7 @@ struct state_decoder { unsigned long int corrupted; double set_fps; // "message" passed to our master + codec_t codec; bool slow; }; @@ -1271,6 +1272,7 @@ static int check_for_mode_change(struct state_decoder *decoder, uint32_t *hdr, s decoder->frame = *frame; ret = TRUE; decoder->set_fps = fps; + decoder->codec = color_spec; } return ret; } @@ -1320,8 +1322,14 @@ int decode_frame(struct coded_data *cdata, void *decode_data) // first, dispatch "messages" if(decoder->set_fps) { - pbuf_data->set_fps = decoder->set_fps; - decoder->set_fps = 0.0; + struct vcodec_message *msg = malloc(sizeof(struct vcodec_message)); + struct fps_changed_message *data = malloc(sizeof(struct fps_changed_message)); + msg->type = FPS_CHANGED; + msg->data = data; + data->val = decoder->set_fps; + data->interframe_codec = is_codec_interframe(decoder->codec); + simple_linked_list_append(pbuf_data->messages, msg); + decoder->set_fps = 0; } int pt; diff --git a/src/rtp/pbuf.c b/src/rtp/pbuf.c index 47ad3e8f4..61d084e6d 100644 --- a/src/rtp/pbuf.c +++ b/src/rtp/pbuf.c @@ -89,6 +89,7 @@ struct pbuf { struct pbuf_node *frst; struct pbuf_node *last; double playout_delay; + double deletion_delay; }; /*********************************************************************************/ @@ -157,7 +158,8 @@ struct pbuf *pbuf_init(void) /* Playout delay... should really be adaptive, based on the */ /* jitter, but we use a (conservative) fixed 32ms delay for */ /* now (2 video frames at 60fps). */ - playout_buf->playout_delay = 0.032; + playout_buf->deletion_delay = + playout_buf->playout_delay = 0.032; } else { debug_msg("Failed to allocate memory for playout buffer\n"); } @@ -193,7 +195,8 @@ static void add_coded_unit(struct pbuf_node *node, rtp_packet * pkt) } } -static struct pbuf_node *create_new_pnode(rtp_packet * pkt, double playout_delay) +static struct pbuf_node *create_new_pnode(rtp_packet * pkt, double playout_delay, + double deletion_delay) { struct pbuf_node *tmp; @@ -211,7 +214,7 @@ static struct pbuf_node *create_new_pnode(rtp_packet * pkt, double playout_delay gettimeofday(&(tmp->playout_time), NULL); tmp->deletion_time = tmp->playout_time; tv_add(&(tmp->playout_time), playout_delay); - tv_add(&(tmp->deletion_time), playout_delay * 2); + tv_add(&(tmp->deletion_time), deletion_delay); tmp->cdata = malloc(sizeof(struct coded_data)); if (tmp->cdata != NULL) { @@ -238,7 +241,8 @@ void pbuf_insert(struct pbuf *playout_buf, rtp_packet * pkt) if (playout_buf->frst == NULL && playout_buf->last == NULL) { /* playout buffer is empty - add new frame */ - playout_buf->frst = create_new_pnode(pkt, playout_buf->playout_delay); + playout_buf->frst = create_new_pnode(pkt, playout_buf->playout_delay, + playout_buf->deletion_delay); playout_buf->last = playout_buf->frst; return; } @@ -250,7 +254,8 @@ void pbuf_insert(struct pbuf *playout_buf, rtp_packet * pkt) } else { if (playout_buf->last->rtp_timestamp < pkt->ts) { /* Packet belongs to a new frame... */ - tmp = create_new_pnode(pkt, playout_buf->playout_delay); + tmp = create_new_pnode(pkt, playout_buf->playout_delay, + playout_buf->deletion_delay); playout_buf->last->nxt = tmp; tmp->prv = playout_buf->last; playout_buf->last = tmp; @@ -407,7 +412,9 @@ audio_pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time, return 0; } -void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay) +void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay, double deletion_delay) { playout_buf->playout_delay = playout_delay; + playout_buf->deletion_delay = deletion_delay; } + diff --git a/src/rtp/pbuf.h b/src/rtp/pbuf.h index fb3e3ef59..b0dfe525f 100644 --- a/src/rtp/pbuf.h +++ b/src/rtp/pbuf.h @@ -68,6 +68,7 @@ #include "video_display.h" #include "audio/audio.h" +#include "utils/list.h" /* The coded representation of a single frame */ struct coded_data { @@ -82,13 +83,23 @@ struct pbuf; struct state_decoder; struct state_audio_decoder; +struct vcodec_message { + enum { FPS_CHANGED } type; + void *data; +}; + +struct fps_changed_message { + double val; + unsigned interframe_codec:1; +}; + struct vcodec_state { struct display *display; struct state_decoder *decoder; unsigned int max_frame_size; // maximal frame size // to be returned to caller by a decoder to allow him adjust buffers accordingly unsigned int decoded; - double set_fps; + struct simple_linked_list *messages; }; struct pbuf_audio_data { @@ -113,6 +124,7 @@ int pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time, decode_frame_t decode_func, void *data); //struct video_frame *framebuffer, int i, struct state_decoder *decoder); void pbuf_remove(struct pbuf *playout_buf, struct timeval curr_time); -void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay); +void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay, + double deletion_delay); diff --git a/src/utils/list.c b/src/utils/list.c new file mode 100644 index 000000000..69709977f --- /dev/null +++ b/src/utils/list.c @@ -0,0 +1,74 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#include "config_unix.h" +#include "config_win32.h" +#endif + +#include "utils/list.h" + +struct node; + +struct node { + void *val; + struct node *next; +}; + +struct simple_linked_list { + struct node *head; + struct node *tail; + int size; +}; + +struct simple_linked_list *simple_linked_list_init(void) +{ + return calloc(1, sizeof(struct simple_linked_list)); +} + +void simple_linked_list_destroy(struct simple_linked_list *l) +{ + struct node *n = l->head; + while(n != NULL) { + struct node *tmp = n; + n = n->next; + free(tmp); + } + free(l); +} + +void simple_linked_list_append(struct simple_linked_list *l, void *data) +{ + struct node *new_node = calloc(1, sizeof(struct node)); + new_node->val = data; + if(l->tail) { + l->tail->next = new_node; + l->tail = l->tail->next; + } else { + l->head = l->tail = new_node; + } + l->size += 1; +} + +void *simple_linked_list_pop(struct simple_linked_list *l) +{ + assert(l->head != NULL); + + struct node *n = l->head; + void *ret; + l->head = l->head->next; + + if(!l->head) + l->tail = NULL; + + l->size--; + + ret = n->val; + free(n); + + return ret; +} + +int simple_linked_list_size(struct simple_linked_list *l) +{ + return l->size; +} + diff --git a/src/utils/list.h b/src/utils/list.h new file mode 100644 index 000000000..e4aae4b1e --- /dev/null +++ b/src/utils/list.h @@ -0,0 +1,20 @@ +#ifndef SIMPLE_LINKED_LIST_H_ +#define SIMPLE_LINKED_LIST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct simple_linked_list; +struct simple_linked_list *simple_linked_list_init(void); +void simple_linked_list_destroy(struct simple_linked_list *); +void simple_linked_list_append(struct simple_linked_list *, void *data); +void *simple_linked_list_pop(struct simple_linked_list *); +int simple_linked_list_size(struct simple_linked_list *); + + +#ifdef __cplusplus +} +#endif + +#endif// SIMPLE_LINKED_LIST_H_ diff --git a/src/video_codec.c b/src/video_codec.c index c9ac29c04..cf18f868f 100644 --- a/src/video_codec.c +++ b/src/video_codec.c @@ -66,26 +66,26 @@ static void vc_copylineToUYVY(unsigned char *dst, const unsigned char *src, int int rshift, int gshift, int bshift, int pix_size); const struct codec_info_t codec_info[] = { - [RGBA] = {RGBA, "RGBA", to_fourcc('R','G','B','A'), 1, 4.0, TRUE, FALSE, "rgba"}, - [UYVY] = {UYVY, "UYVY", to_fourcc('2','v','u','y'), 1, 2, FALSE, FALSE, "yuv"}, - [YUYV] = {YUYV, "YUYV", to_fourcc('Y','U','Y','V'), 1, 2, FALSE, FALSE, "yuv"}, - [Vuy2] = {Vuy2, "2vuy", to_fourcc('2','V','u','y'), 1, 2, FALSE, FALSE, "yuv"}, - [DVS8] = {DVS8, "DVS8", to_fourcc('d','v','s','8'), 1, 2, FALSE, FALSE, "yuv"}, - [R10k] = {R10k, "R10k", to_fourcc('R','1','0','k'), 1, 4, TRUE, FALSE, "r10k"}, - [v210] = {v210, "v210", to_fourcc('v','2','1','0'), 48, 8.0 / 3.0, FALSE, FALSE, "v210"}, - [DVS10] = {DVS10, "DVS10", to_fourcc('D','S','1','0'), 48, 8.0 / 3.0, FALSE, FALSE, "dvs10"}, - [DXT1] = {DXT1, "DXT1", to_fourcc('D','X','T','1'), 1, 0.5, TRUE, TRUE, "dxt1"}, - [DXT1_YUV] = {DXT1_YUV, "DXT1 YUV", to_fourcc('D','X','T','Y'), 1, 0.5, FALSE, TRUE, "dxt1y"}, /* packet YCbCr inside DXT1 channels */ - [DXT5] = {DXT5, "DXT5", to_fourcc('D','X','T','5'), 1, 1.0, FALSE, TRUE, "yog"},/* DXT5 YCoCg */ - [RGB] = {RGB, "RGB", to_fourcc('R','G','B','2'), 1, 3.0, TRUE, FALSE, "rgb"}, - [DPX10] = {DPX10, "DPX10", to_fourcc('D','P','1','0'), 1, 4.0, TRUE, FALSE, "dpx"}, - [JPEG] = {JPEG, "JPEG", to_fourcc('J','P','E','G'), 0, 0.0, FALSE, TRUE, "jpg"}, - [RAW] = {RAW, "raw", to_fourcc('r','a','w','s'), 0, 1.0, FALSE, TRUE, "raw"}, /* raw SDI */ - [H264] = {H264, "H.264", to_fourcc('A','V','C','1'), 0, 1.0, FALSE, TRUE, "h264"}, - [MJPG] = {MJPG, "MJPEG", to_fourcc('M','J','P','G'), 0, 1.0, FALSE, TRUE, "jpg"}, - [VP8] = {VP8, "VP8", to_fourcc('V','P','8','0'), 0, 1.0, FALSE, TRUE, "vp8"}, - [BGR] = {BGR, "BGR", to_fourcc('B','G','R','2'), 1, 3.0, TRUE, FALSE, "bgr"}, - {(codec_t) 0, NULL, 0, 0, 0.0, FALSE, FALSE, NULL} + [RGBA] = {RGBA, "RGBA", to_fourcc('R','G','B','A'), 1, 4.0, TRUE, FALSE, FALSE, "rgba"}, + [UYVY] = {UYVY, "UYVY", to_fourcc('2','v','u','y'), 1, 2, FALSE, FALSE, FALSE, "yuv"}, + [YUYV] = {YUYV, "YUYV", to_fourcc('Y','U','Y','V'), 1, 2, FALSE, FALSE, FALSE, "yuv"}, + [Vuy2] = {Vuy2, "2vuy", to_fourcc('2','V','u','y'), 1, 2, FALSE, FALSE, FALSE, "yuv"}, + [DVS8] = {DVS8, "DVS8", to_fourcc('d','v','s','8'), 1, 2, FALSE, FALSE, FALSE, "yuv"}, + [R10k] = {R10k, "R10k", to_fourcc('R','1','0','k'), 1, 4, TRUE, FALSE, FALSE, "r10k"}, + [v210] = {v210, "v210", to_fourcc('v','2','1','0'), 48, 8.0 / 3.0, FALSE, FALSE, FALSE, "v210"}, + [DVS10] = {DVS10, "DVS10", to_fourcc('D','S','1','0'), 48, 8.0 / 3.0, FALSE, FALSE, FALSE, "dvs10"}, + [DXT1] = {DXT1, "DXT1", to_fourcc('D','X','T','1'), 1, 0.5, TRUE, TRUE, FALSE, "dxt1"}, + [DXT1_YUV] = {DXT1_YUV, "DXT1 YUV", to_fourcc('D','X','T','Y'), 1, 0.5, FALSE, TRUE, FALSE, "dxt1y"}, /* packet YCbCr inside DXT1 channels */ + [DXT5] = {DXT5, "DXT5", to_fourcc('D','X','T','5'), 1, 1.0, FALSE, TRUE, FALSE, "yog"},/* DXT5 YCoCg */ + [RGB] = {RGB, "RGB", to_fourcc('R','G','B','2'), 1, 3.0, TRUE, FALSE, FALSE, "rgb"}, + [DPX10] = {DPX10, "DPX10", to_fourcc('D','P','1','0'), 1, 4.0, TRUE, FALSE, FALSE, "dpx"}, + [JPEG] = {JPEG, "JPEG", to_fourcc('J','P','E','G'), 0, 0.0, FALSE, TRUE, FALSE, "jpg"}, + [RAW] = {RAW, "raw", to_fourcc('r','a','w','s'), 0, 1.0, FALSE, TRUE, FALSE, "raw"}, /* raw SDI */ + [H264] = {H264, "H.264", to_fourcc('A','V','C','1'), 0, 1.0, FALSE, TRUE, TRUE, "h264"}, + [MJPG] = {MJPG, "MJPEG", to_fourcc('M','J','P','G'), 0, 1.0, FALSE, TRUE, FALSE, "jpg"}, + [VP8] = {VP8, "VP8", to_fourcc('V','P','8','0'), 0, 1.0, FALSE, TRUE, TRUE, "vp8"}, + [BGR] = {BGR, "BGR", to_fourcc('B','G','R','2'), 1, 3.0, TRUE, FALSE, FALSE, "bgr"}, + {(codec_t) 0, NULL, 0, 0, 0.0, FALSE, FALSE, FALSE, NULL} }; /* take care that UYVY is alias for both 2vuy and dvs8, do not use @@ -247,6 +247,18 @@ int is_codec_opaque(codec_t codec) return 0; } +int is_codec_interframe(codec_t codec) +{ + int i = 0; + + while (codec_info[i].name != NULL) { + if (codec == codec_info[i].codec) + return codec_info[i].interframe; + i++; + } + return 0; +} + static int get_halign(codec_t codec) { int i = 0; diff --git a/src/video_codec.h b/src/video_codec.h index 1eac9d8b7..13d05abb0 100644 --- a/src/video_codec.h +++ b/src/video_codec.h @@ -70,6 +70,7 @@ struct codec_info_t { double bpp; unsigned rgb:1; unsigned opaque:1; + unsigned interframe:1; const char *file_extension; }; @@ -87,6 +88,7 @@ double get_bpp(codec_t codec); uint32_t get_fourcc(codec_t codec); const char *get_codec_name(codec_t codec); int is_codec_opaque(codec_t codec); +int is_codec_interframe(codec_t codec); codec_t get_codec_from_fcc(uint32_t fourcc); const char *get_codec_file_extension(codec_t codec);