Video postprocess: moved from decoder to display

This allows postprocess replacement without reconfiguring the whole
decoder (under smoe circumstances).
This commit is contained in:
Martin Pulec
2016-07-22 13:08:59 +02:00
parent c356176219
commit 5197a11c85
11 changed files with 236 additions and 30 deletions

View File

@@ -509,10 +509,10 @@ static int process_msg(struct control_state *s, fd_t client_fd, char *message, s
msg->type = RECEIVER_MSG_MUTE;
resp = send_message(s->root_module, path, (struct message *) msg);
} else if (prefix_matches(message, "postprocess ")) {
strncpy(path, "receiver", sizeof path);
struct msg_receiver *msg = (struct msg_receiver *) new_message(sizeof(struct msg_receiver));
msg->type = RECEIVER_MSG_POSTPROCESS;
strncpy(msg->postprocess_cfg, suffix(message, "postprocess "), sizeof msg->postprocess_cfg - 1);
strncpy(path, "display", sizeof path);
struct msg_universal *msg = (struct msg_universal *) new_message(sizeof(struct msg_universal));
strncpy(msg->text, message, sizeof msg->text - 1);
msg->text[sizeof msg->text - 1] = '\0';
resp = send_message(s->root_module, path, (struct message *) msg);
} else if(strcasecmp(message, "bye") == 0) {
ret = CONTROL_CLOSE_HANDLE;

View File

@@ -197,11 +197,11 @@ void *hd_rum_decompress_init(struct module *parent, bool blend, const char *capt
if (blend) {
char cfg[128] = "";
snprintf(cfg, sizeof cfg, "pipe:%p", s);
assert (initialize_video_display(parent, "proxy", cfg, 0, &s->display) == 0);
assert (initialize_video_display(parent, "proxy", cfg, 0, NULL, &s->display) == 0);
} else {
char cfg[2 + sizeof(void *) * 2 + 1] = "";
snprintf(cfg, sizeof cfg, "%p", s);
assert (initialize_video_display(parent, "pipe", cfg, 0, &s->display) == 0);
assert (initialize_video_display(parent, "pipe", cfg, 0, NULL, &s->display) == 0);
}
map<string, param_u> params;

View File

@@ -1030,7 +1030,7 @@ int main(int argc, char *argv[])
// Display initialization should be prior to modules that may use graphic card (eg. GLSL) in order
// to initalize shared resource (X display) first
ret =
initialize_video_display(&uv.root_module, requested_display, display_cfg, display_flags, &uv.display_device);
initialize_video_display(&uv.root_module, requested_display, display_cfg, display_flags, postprocess, &uv.display_device);
if (ret < 0) {
printf("Unable to open display device: %s\n",
requested_display);
@@ -1132,7 +1132,7 @@ int main(int argc, char *argv[])
params["video_delay"].ptr = (void *) &video_offset;
// UltraGrid RTP
params["postprocess"].ptr = (void *) postprocess;
params["postprocess"].ptr = (void *) NULL;
params["decoder_mode"].l = (long) decoder_mode;
params["display_device"].ptr = uv.display_device;

View File

@@ -1170,7 +1170,7 @@ static bool reconfigure_decoder(struct state_video_decoder *decoder,
{
int ret;
/* reconfigure VO and give it opportunity to pass us pitch */
ret = display_reconfigure(decoder->display, display_desc);
ret = display_reconfigure(decoder->display, display_desc, decoder->video_mode);
if(!ret) {
log_msg(LOG_LEVEL_ERROR, "[decoder] Unable to reconfigure display.\n");
return false;
@@ -1215,6 +1215,7 @@ static bool reconfigure_decoder(struct state_video_decoder *decoder,
decoder->pitch = vc_get_linesize(linewidth, out_codec);
}
if(decoder->display_requested_pitch == PITCH_DEFAULT) {
decoder->display_pitch = vc_get_linesize(display_desc.width, out_codec);
} else {

View File

@@ -102,7 +102,7 @@ static int vidcap_ug_input_init(const struct vidcap_params *cap_params, void **s
char cfg[128] = "";
snprintf(cfg, sizeof cfg, "pipe:%p", s);
assert (initialize_video_display(vidcap_params_get_parent(cap_params), "proxy", cfg, 0, &s->display) == 0);
assert (initialize_video_display(vidcap_params_get_parent(cap_params), "proxy", cfg, 0, NULL, &s->display) == 0);
map<string, param_u> params;

View File

@@ -52,6 +52,12 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @todo
* On-fly postprocess reconfiguration is not ok in general case. The pitch or
* supported codecs might have changed due to the reconfiguration, which is,
* however, not reflected by decoder which queried the data before.
*/
#include "config.h"
#include "config_unix.h"
@@ -60,7 +66,9 @@
#include "lib_common.h"
#include "module.h"
#include "perf.h"
#include "video.h"
#include "video_display.h"
#include "vo_postprocess.h"
#define DISPLAY_MAGIC 0x01ba7ef1
@@ -70,6 +78,11 @@ struct display {
uint32_t magic; ///< For debugging. Conatins @ref DISPLAY_MAGIC
const struct video_display_info *funcs;
void *state; ///< state of the created video capture driver
struct vo_postprocess_state *postprocess;
int pp_output_frames_count, display_pitch;
struct video_desc saved_desc;
enum video_mode saved_mode;
};
/**This variable represents a pseudostate and may be returned when initialization
@@ -97,8 +110,13 @@ void list_video_display_devices()
* @retval 1 if successfully shown help (no state returned)
*/
int initialize_video_display(struct module *parent, const char *requested_display,
const char *fmt, unsigned int flags, struct display **out)
const char *fmt, unsigned int flags, const char *postprocess, struct display **out)
{
if (postprocess && strcmp(postprocess, "help") == 0) {
show_vo_postprocess_help();
return 1;
}
const struct video_display_info *vdi = (const struct video_display_info *)
load_library(requested_display, LIBRARY_CLASS_VIDEO_DISPLAY, VIDEO_DISPLAY_ABI_VERSION);
@@ -124,6 +142,15 @@ int initialize_video_display(struct module *parent, const char *requested_displa
free(d);
return 1;
}
if (postprocess) {
d->postprocess = vo_postprocess_init(postprocess);
if (!d->postprocess) {
display_done(d);
return 1;
}
}
*out = d;
return 0;
}
@@ -142,6 +169,7 @@ void display_done(struct display *d)
assert(d->magic == DISPLAY_MAGIC);
d->funcs->done(d->state);
module_done(&d->mod);
vo_postprocess_done(d->postprocess);
free(d);
}
@@ -163,6 +191,37 @@ void display_run(struct display *d)
d->funcs->run(d->state);
}
static struct response *process_message(struct display *d, struct msg_universal *msg)
{
if (strncasecmp(msg->text, "postprocess ", strlen("postprocess ")) == 0) {
log_msg(LOG_LEVEL_WARNING, "On fly changing postprocessing is currently "
"only an experimental feature! Use with caution!\n");
const char *text = msg->text + strlen("postprocess ");
struct vo_postprocess_state *postprocess_old = d->postprocess;
if (strcmp(text, "flush") != 0) {
d->postprocess = vo_postprocess_init(text);
if (!d->postprocess) {
d->postprocess = postprocess_old;
log_msg(LOG_LEVEL_ERROR, "Unable to create postprocess '%s'.\n", text);
return new_response(RESPONSE_BAD_REQUEST, NULL);
}
} else {
d->postprocess = NULL;
}
vo_postprocess_done(postprocess_old);
display_reconfigure(d, d->saved_desc, d->saved_mode);
return new_response(RESPONSE_OK, NULL);
} else {
log_msg(LOG_LEVEL_ERROR, "Unknown command '%s'.\n", msg->text);
return new_response(RESPONSE_BAD_REQUEST, NULL);
}
}
/**
* @brief Returns video framebuffer which will be written to.
*
@@ -174,9 +233,19 @@ void display_run(struct display *d)
*/
struct video_frame *display_get_frame(struct display *d)
{
struct message *msg;
while((msg = check_message(&d->mod))) {
struct response *r = process_message(d, (struct msg_universal *) msg);
free_message(msg, r);
}
perf_record(UVP_GETFRAME, d);
assert(d->magic == DISPLAY_MAGIC);
return d->funcs->getf(d->state);
if (d->postprocess) {
return vo_postprocess_getf(d->postprocess);
} else {
return d->funcs->getf(d->state);
}
}
/**
@@ -186,13 +255,39 @@ struct video_frame *display_get_frame(struct display *d)
* @param d display to be putted frame to
* @param frame frame that has been obtained from display_get_frame() and has not yet been put.
* Should not be NULL unless we want to quit display mainloop.
* @param nonblock specifies blocking behavior (@ref display_put_frame_flags)
* @param flags specifies blocking behavior (@ref display_put_frame_flags)
* @retval 0 if displayed succesfully
* @retval 1 if not displayed
*/
int display_put_frame(struct display *d, struct video_frame *frame, int nonblock)
int display_put_frame(struct display *d, struct video_frame *frame, int flags)
{
perf_record(UVP_PUTFRAME, frame);
assert(d->magic == DISPLAY_MAGIC);
return d->funcs->putf(d->state, frame, nonblock);
if (!frame) {
return d->funcs->putf(d->state, frame, flags);
}
if (d->postprocess) {
int display_ret = 0;
for (int i = 0; i < d->pp_output_frames_count; ++i) {
struct video_frame *display_frame = d->funcs->getf(d->state);
int ret = vo_postprocess(d->postprocess,
frame,
display_frame,
d->display_pitch);
frame = NULL;
if (!ret) {
d->funcs->putf(d->state, display_frame, PUTF_DISCARD);
return 1;
}
display_ret = d->funcs->putf(d->state, display_frame, flags);
}
return display_ret;
} else {
return d->funcs->putf(d->state, frame, flags);
}
}
/**
@@ -207,10 +302,77 @@ int display_put_frame(struct display *d, struct video_frame *frame, int nonblock
* @retval TRUE if reconfiguration succeeded
* @retval FALSE if reconfiguration failed
*/
int display_reconfigure(struct display *d, struct video_desc desc)
int display_reconfigure(struct display *d, struct video_desc desc, enum video_mode video_mode)
{
assert(d->magic == DISPLAY_MAGIC);
return d->funcs->reconfigure_video(d->state, desc);
d->saved_desc = desc;
d->saved_mode = video_mode;
if (d->postprocess) {
bool pp_does_change_tiling_mode = false;
size_t len = sizeof(pp_does_change_tiling_mode);
if (vo_postprocess_get_property(d->postprocess, VO_PP_DOES_CHANGE_TILING_MODE,
&pp_does_change_tiling_mode, &len)) {
if(len == 0) {
// just for sake of completness since it shouldn't be a case
log_msg(LOG_LEVEL_WARNING, "Warning: unable to get pp tiling mode!\n");
}
}
struct video_desc pp_desc = desc;
if (!pp_does_change_tiling_mode) {
pp_desc.width *= get_video_mode_tiles_x(video_mode);
pp_desc.height *= get_video_mode_tiles_y(video_mode);
pp_desc.tile_count = 1;
}
if (!vo_postprocess_reconfigure(d->postprocess, pp_desc)) {
log_msg(LOG_LEVEL_ERROR, "[video dec.] Unable to reconfigure video "
"postprocess.\n");
return false;
}
struct video_desc display_desc;
int render_mode; // WTF ?
vo_postprocess_get_out_desc(d->postprocess, &display_desc, &render_mode, &d->pp_output_frames_count);
int rc = d->funcs->reconfigure_video(d->state, display_desc);
len = sizeof d->display_pitch;
d->display_pitch = PITCH_DEFAULT;
d->funcs->get_property(d->state, DISPLAY_PROPERTY_BUF_PITCH,
&d->display_pitch, &len);
if (d->display_pitch == PITCH_DEFAULT) {
d->display_pitch = vc_get_linesize(display_desc.width, display_desc.color_spec);
}
return rc;
} else {
return d->funcs->reconfigure_video(d->state, desc);
}
}
static void restrict_returned_codecs(codec_t *display_codecs,
size_t *display_codecs_count, codec_t *pp_codecs,
int pp_codecs_count)
{
int i;
for (i = 0; i < (int) *display_codecs_count; ++i) {
int j;
int found = FALSE;
for (j = 0; j < pp_codecs_count; ++j) {
if(display_codecs[i] == pp_codecs[j]) {
found = TRUE;
}
}
if(!found) {
memmove(&display_codecs[i], (const void *) &display_codecs[i + 1],
sizeof(codec_t) * (*display_codecs_count - i - 1));
--*display_codecs_count;
--i;
}
}
}
/**
@@ -226,7 +388,50 @@ int display_reconfigure(struct display *d, struct video_desc desc)
int display_get_property(struct display *d, int property, void *val, size_t *len)
{
assert(d->magic == DISPLAY_MAGIC);
return d->funcs->get_property(d->state, property, val, len);
if (d->postprocess) {
switch (property) {
case DISPLAY_PROPERTY_BUF_PITCH:
*(int *) val = PITCH_DEFAULT;
*len = sizeof(int);
return TRUE;
case DISPLAY_PROPERTY_CODECS:
{
codec_t display_codecs[20], pp_codecs[20];
size_t display_codecs_count, pp_codecs_count;
size_t nlen;
bool ret;
nlen = sizeof display_codecs;
ret = d->funcs->get_property(d->state, DISPLAY_PROPERTY_CODECS, display_codecs, &nlen);
if (!ret) return FALSE;
display_codecs_count = nlen / sizeof(codec_t);
nlen = sizeof pp_codecs;
ret = vo_postprocess_get_property(d->postprocess, VO_PP_PROPERTY_CODECS, pp_codecs, &nlen);
if (ret) {
if (nlen == 0) { // problem detected
log_msg(LOG_LEVEL_ERROR, "[Decoder] Unable to get supported codecs.\n");
return FALSE;
}
pp_codecs_count = nlen / sizeof(codec_t);
restrict_returned_codecs(display_codecs, &display_codecs_count,
pp_codecs, pp_codecs_count);
}
nlen = display_codecs_count * sizeof(codec_t);
if (nlen <= *len) {
*len = nlen;
memcpy(val, display_codecs, nlen);
return TRUE;
} else {
return FALSE;
}
}
break;
default:
return d->funcs->get_property(d->state, property, val, len);
}
} else {
return d->funcs->get_property(d->state, property, val, len);
}
}
/**

View File

@@ -161,20 +161,20 @@ extern int display_init_noerr;
void list_video_display_devices(void);
int initialize_video_display(struct module *parent,
const char *requested_display, const char *fmt, unsigned int flags,
struct display **out);
const char *postprocess, struct display **out);
void display_run(struct display *d);
void display_done(struct display *d);
struct video_frame *display_get_frame(struct display *d);
/** @brief putf blocking behavior control */
/** @brief putf flags */
enum display_put_frame_flags {
PUTF_BLOCKING = 0, ///< Block until frame can be displayed.
PUTF_NONBLOCK = 1, ///< Do not block.
PUTF_DISCARD = 2,
};
int display_put_frame(struct display *d, struct video_frame *frame, int nonblock);
int display_reconfigure(struct display *d, struct video_desc desc);
int display_put_frame(struct display *d, struct video_frame *frame, int flags);
int display_reconfigure(struct display *d, struct video_desc desc, enum video_mode mode);
int display_get_property(struct display *d, int property, void *val, size_t *len);
/**
* @defgroup display_audio Audio

View File

@@ -152,7 +152,7 @@ static void *display_aggregate_init(struct module *parent, const char *fmt, unsi
}
int ret = initialize_video_display(parent, device,
device_cfg, dev_flags, &s->devices[i]);
device_cfg, dev_flags, NULL, &s->devices[i]);
if(ret != 0) {
fprintf(stderr, "[aggregate] Unable to initialize device %d (%s:%s).\n", i, device, device_cfg);
free(config);
@@ -252,7 +252,7 @@ static int display_aggregate_reconfigure(void *state, struct video_desc desc)
desc.tile_count = 1;
for(i = 0; i < s->devices_cnt; ++i) {
ret = display_reconfigure(s->devices[i], desc);
ret = display_reconfigure(s->devices[i], desc, VIDEO_NORMAL);
if(!ret)
break;
}

View File

@@ -59,7 +59,7 @@ static struct display *display_pipe_fork(void *state)
snprintf(fmt, sizeof fmt, "%p", s->delegate);
int rc = initialize_video_display(s->parent,
"pipe", fmt, 0, &out);
"pipe", fmt, 0, NULL, &out);
if (rc == 0) return out; else return NULL;
}

View File

@@ -108,7 +108,7 @@ static struct display *display_proxy_fork(void *state)
snprintf(fmt, sizeof fmt, "%p", state);
int rc = initialize_video_display(s->parent,
"proxy", fmt, 0, &out);
"proxy", fmt, 0, NULL, &out);
if (rc == 0) return out; else return NULL;
return out;
@@ -140,7 +140,7 @@ static void *display_proxy_init(struct module *parent, const char *fmt, unsigned
}
}
s->common = shared_ptr<state_proxy_common>(new state_proxy_common());
assert (initialize_video_display(parent, requested_display, cfg, flags, &s->common->real_display) == 0);
assert (initialize_video_display(parent, requested_display, cfg, flags, NULL, &s->common->real_display) == 0);
free(fmt_copy);
int ret = pthread_create(&s->common->thread_id, NULL, (void *(*)(void *)) display_run,
@@ -157,7 +157,7 @@ static void check_reconf(struct state_proxy_common *s, struct video_desc desc)
if (!video_desc_eq(desc, s->display_desc)) {
s->display_desc = desc;
fprintf(stderr, "RECONFIGURED\n");
display_reconfigure(s->real_display, s->display_desc);
display_reconfigure(s->real_display, s->display_desc, VIDEO_NORMAL);
}
}

View File

@@ -66,7 +66,7 @@ sage_video_rxtx::sage_video_rxtx(map<string, param_u> const &params) :
oss << "fs=" << static_cast<const char *>(params.at("receiver").ptr);
oss << ":tx"; // indicates that we are in tx mode
int ret = initialize_video_display(&m_sender_mod, "sage",
oss.str().c_str(), 0, &m_sage_tx_device);
oss.str().c_str(), 0, NULL, &m_sage_tx_device);
if(ret != 0) {
throw string("Unable to initialize SAGE TX.");
}
@@ -81,7 +81,7 @@ void sage_video_rxtx::send_frame(shared_ptr<video_frame> tx_frame)
if(!video_desc_eq(m_saved_video_desc,
video_desc_from_frame(tx_frame.get()))) {
display_reconfigure(m_sage_tx_device,
video_desc_from_frame(tx_frame.get()));
video_desc_from_frame(tx_frame.get()), VIDEO_NORMAL);
m_saved_video_desc = video_desc_from_frame(tx_frame.get());
}
struct video_frame *frame =