From 88ee65c66bbc04c7ed0127a56742e1ecd03aeffe Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Wed, 12 Nov 2014 15:31:45 +0100 Subject: [PATCH] Added transition from LFF to interlaced merged --- src/rtp/video_decoders.cpp | 14 +++++++-- src/video_frame.c | 60 ++++++++++++++++++++++++++++++++++++-- src/video_frame.h | 5 ++-- 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/rtp/video_decoders.cpp b/src/rtp/video_decoders.cpp index 7be55659c..556de1e78 100644 --- a/src/rtp/video_decoders.cpp +++ b/src/rtp/video_decoders.cpp @@ -109,7 +109,7 @@ struct state_video_decoder; * Interlacing changing function protoype. The function should be able to change buffer * in place, that is when dst and src are the same. */ -typedef void (*change_il_t)(char *dst, char *src, int linesize, int height); +typedef void (*change_il_t)(char *dst, char *src, int linesize, int height, void **state); // prototypes static bool reconfigure_decoder(struct state_video_decoder *decoder, @@ -216,6 +216,7 @@ struct state_video_decoder unsigned int max_substreams; ///< maximal number of expected substreams change_il_t change_il; ///< function to change interlacing, if needed. Otherwise NULL. + vector change_il_state; mutex lock; @@ -526,7 +527,7 @@ static void *decompress_thread(void *args) { for(i = 0; i < decoder->frame->tile_count; ++i) { struct tile *tile = vf_get_tile(decoder->frame, i); decoder->change_il(tile->data, tile->data, vc_get_linesize(tile->width, - decoder->out_codec), tile->height); + decoder->out_codec), tile->height, &decoder->change_il_state[i]); } } @@ -782,6 +783,11 @@ static void cleanup(struct state_video_decoder *decoder) free(decoder->line_decoder); decoder->line_decoder = NULL; } + + for (auto && item : decoder->change_il_state) { + free(item); + } + decoder->change_il_state.resize(0); } #define PRINT_STATISTICS fprintf(stderr, "Video decoder statistics: %lu total: %lu displayed / %lu "\ @@ -1039,6 +1045,7 @@ static change_il_t select_il_func(enum interlacing_t in_il, enum interlacing_t * struct transcode_t { enum interlacing_t in; enum interlacing_t out; change_il_t func; }; struct transcode_t transcode[] = { + {LOWER_FIELD_FIRST, INTERLACED_MERGED, il_lower_to_merged}, {UPPER_FIELD_FIRST, INTERLACED_MERGED, il_upper_to_merged}, {INTERLACED_MERGED, UPPER_FIELD_FIRST, il_merged_to_upper} }; @@ -1062,6 +1069,8 @@ static change_il_t select_il_func(enum interlacing_t in_il, enum interlacing_t * } } + fprintf(stderr, "[Warning] Cannot find transition between incoming and display " + "interlacing modes!\n"); return NULL; } @@ -1146,6 +1155,7 @@ static bool reconfigure_decoder(struct state_video_decoder *decoder, decoder->change_il = select_il_func(desc.interlacing, decoder->disp_supported_il, decoder->disp_supported_il_cnt, &display_il); + decoder->change_il_state.resize(decoder->max_substreams); if (!decoder->postprocess || !pp_does_change_tiling_mode) { /* otherwise we need postprocessor mode, which we obtained before */ render_mode = display_mode; diff --git a/src/video_frame.c b/src/video_frame.c index fefa8407a..9b62200f9 100644 --- a/src/video_frame.c +++ b/src/video_frame.c @@ -211,9 +211,62 @@ const char *get_interlacing_suffix(enum interlacing_t interlacing) return NULL; } -/* TODO: rewrite following 2 functions in more efficient way */ -void il_upper_to_merged(char *dst, char *src, int linesize, int height) +/** + * @todo + * Needs to be more efficient + */ +void il_lower_to_merged(char *dst, char *src, int linesize, int height, void **stored_state) { + struct il_lower_to_merged_state { + size_t field_len; + char field[]; + }; + struct il_lower_to_merged_state *last_field = (struct il_lower_to_merged_state *) *stored_state; + + int y; + char *tmp = malloc(linesize * height); + char *line1, *line2; + + // upper field + line1 = tmp; + int field_len = linesize * (height / 2); + // first check if we have field from last frame + if (last_field == NULL) { + last_field = (struct il_lower_to_merged_state *) + malloc(sizeof(struct il_lower_to_merged_state) + field_len); + last_field->field_len = field_len; + *stored_state = last_field; + // if no, use current one + line2 = src + linesize * ((height + 1) / 2); + } else { + // otherwise use field from last "frame" + line2 = last_field->field; + } + for(y = 0; y < height / 2; y ++) { + memcpy(line1, line2, linesize); + line1 += linesize * 2; + line2 += linesize; + } + // store + assert ((int) last_field->field_len == field_len); + memcpy(last_field->field, src + linesize * ((height + 1) / 2), field_len); + + // lower field + line1 = tmp + linesize; + line2 = src; + for(y = 0; y < (height + 1) / 2; y ++) { + memcpy(line1, line2, linesize); + line1 += linesize * 2; + line2 += linesize; + } + memcpy(dst, tmp, linesize * height); + free(tmp); +} + +/* TODO: rewrite following 2 functions in more efficient way */ +void il_upper_to_merged(char *dst, char *src, int linesize, int height, void **state) +{ + UNUSED(state); int y; char *tmp = malloc(linesize * height); char *line1, *line2; @@ -237,8 +290,9 @@ void il_upper_to_merged(char *dst, char *src, int linesize, int height) free(tmp); } -void il_merged_to_upper(char *dst, char *src, int linesize, int height) +void il_merged_to_upper(char *dst, char *src, int linesize, int height, void **state) { + UNUSED(state); int y; char *tmp = malloc(linesize * height); char *line1, *line2; diff --git a/src/video_frame.h b/src/video_frame.h index db3ebe896..975335c8f 100644 --- a/src/video_frame.h +++ b/src/video_frame.h @@ -151,15 +151,16 @@ const char *get_interlacing_description(enum interlacing_t interlacing); */ const char *get_interlacing_suffix(enum interlacing_t interlacing); +void il_lower_to_merged(char *dst, char *src, int linesize, int height, void **stored_state); /* these functions transcode one interlacing format to another */ /** * @brief Converts upper-field-first to interlaced merged. */ -void il_upper_to_merged(char *dst, char *src, int linesize, int height); +void il_upper_to_merged(char *dst, char *src, int linesize, int height, void **stored_state); /** * @brief Converts interlaced merged to upper-field-first. */ -void il_merged_to_upper(char *dst, char *src, int linesize, int height); +void il_merged_to_upper(char *dst, char *src, int linesize, int height, void **stored_state); /** * @brief Computes FPS as a double from packet fields.