mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-04-03 23:04:25 +00:00
do not deinterlace progressive
until option "force" is given, do not deinterlace progressive video
This commit is contained in:
@@ -692,6 +692,8 @@ static void vc_deinterlace_unaligned(unsigned char *src, long src_linesize, int
|
||||
*
|
||||
* @returns false on unsupported codecs
|
||||
*/
|
||||
// Sibling of this function is in double-framerate.cpp:avg_lines so consider
|
||||
// porting changes made here there.
|
||||
bool vc_deinterlace_ex(codec_t codec, unsigned char *src, size_t src_linesize, unsigned char *dst, size_t dst_pitch, size_t lines)
|
||||
{
|
||||
if (is_codec_opaque(codec) && codec_is_planar(codec)) {
|
||||
|
||||
@@ -347,7 +347,7 @@ struct state_gl {
|
||||
GLFWwindow *window = nullptr;
|
||||
|
||||
bool fs = false;
|
||||
bool deinterlace = false;
|
||||
enum class deint { off, on, force } deinterlace = deint::off;
|
||||
|
||||
struct video_frame *current_frame = nullptr;
|
||||
|
||||
@@ -385,10 +385,10 @@ struct state_gl {
|
||||
enum modeset_t { MODESET = -2, MODESET_SIZE_ONLY = GLFW_DONT_CARE, NOMODESET = 0 } modeset = NOMODESET; ///< positive vals force framerate
|
||||
bool nodecorate = false;
|
||||
int use_pbo = -1;
|
||||
|
||||
#ifdef HWACC_VDPAU
|
||||
struct state_vdpau vdp;
|
||||
#endif
|
||||
vector<char> scratchpad; ///< scratchpad sized WxHx8
|
||||
|
||||
state_gl(struct module *parent) {
|
||||
glfwSetErrorCallback(glfw_print_error);
|
||||
@@ -408,7 +408,14 @@ struct state_gl {
|
||||
module_done(&mod);
|
||||
}
|
||||
|
||||
vector<char> scratchpad; ///< scratchpad sized WxHx8
|
||||
static const char *deint_to_string(state_gl::deint val) {
|
||||
switch (val) {
|
||||
case state_gl::deint::off: return "OFF";
|
||||
case state_gl::deint::on: return "ON";
|
||||
case state_gl::deint::force: return "FORCE";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr array gl_supp_codecs = {
|
||||
@@ -477,7 +484,7 @@ static void gl_show_help(bool full) {
|
||||
col() << "options:\n";
|
||||
col() << TBOLD("\taspect=<w>/<h>") << "\trequested video aspect (eg. 16/9). Leave unset if PAR = 1.\n";
|
||||
col() << TBOLD("\tcursor") << "\t\tshow visible cursor\n";
|
||||
col() << TBOLD("\td") << "\t\tdeinterlace\n";
|
||||
col() << TBOLD("\td[force]") << "\tdeinterlace (optionally forcing deinterlace of progressive video)\n";
|
||||
col() << TBOLD("\tfs[=<monitor>]") << "\tfullscreen with optional display specification\n";
|
||||
col() << TBOLD("\tgamma[=<val>]") << "\tgamma value to be added _in addition_ to the hardware gamma correction\n";
|
||||
col() << TBOLD("\thide-window") << "\tdo not show OpenGL window (useful with Syphon/SPOUT)\n";
|
||||
@@ -549,8 +556,8 @@ static void *display_gl_parse_fmt(struct state_gl *s, char *ptr) {
|
||||
char *tok, *save_ptr = NULL;
|
||||
|
||||
while((tok = strtok_r(ptr, ":", &save_ptr)) != NULL) {
|
||||
if(!strcmp(tok, "d")) {
|
||||
s->deinterlace = true;
|
||||
if (!strcmp(tok, "d") || !strcmp(tok, "dforce")) {
|
||||
s->deinterlace = !strcmp(tok, "d") ? state_gl::deint::on : state_gl::deint::force;
|
||||
} else if(!strncmp(tok, "fs", 2)) {
|
||||
s->fs = true;
|
||||
if (char *val = strchr(tok, '=')) {
|
||||
@@ -663,7 +670,7 @@ static void * display_gl_init(struct module *parent, const char *fmt, unsigned i
|
||||
s->use_pbo = s->use_pbo == -1 ? !check_rpi_pbo_quirks() : s->use_pbo; // don't use PBO for Raspberry Pi (better performance)
|
||||
|
||||
log_msg(LOG_LEVEL_INFO,"GL setup: fullscreen: %s, deinterlace: %s\n",
|
||||
s->fs ? "ON" : "OFF", s->deinterlace ? "ON" : "OFF");
|
||||
s->fs ? "ON" : "OFF", state_gl::deint_to_string(s->deinterlace));
|
||||
|
||||
gl_load_splashscreen(s);
|
||||
for (auto const &i : keybindings) {
|
||||
@@ -694,6 +701,9 @@ static int display_gl_reconfigure(void *state, struct video_desc desc)
|
||||
if (get_bits_per_component(desc.color_spec) > 8) {
|
||||
LOG(LOG_LEVEL_WARNING) << MOD_NAME "Displaying 10+ bits - performance degradation may occur, consider '--param " GL_DISABLE_10B_OPT_PARAM_NAME "'\n";
|
||||
}
|
||||
if (desc.interlacing == INTERLACED_MERGED && s->deinterlace == state_gl::deint::off) {
|
||||
LOG(LOG_LEVEL_WARNING) << MOD_NAME "Receiving interlaced video but deinterlacing is off - suggesting toggling it on (press 'd' or pass cmdline option)\n";
|
||||
}
|
||||
|
||||
s->current_desc = desc;
|
||||
|
||||
@@ -953,7 +963,7 @@ static void gl_reconfigure_screen(struct state_gl *s, struct video_desc desc)
|
||||
|
||||
static void gl_render(struct state_gl *s, char *data)
|
||||
{
|
||||
if (s->deinterlace) {
|
||||
if (s->deinterlace == state_gl::deint::force || (s->deinterlace == state_gl::deint::on && s->current_display_desc.interlacing == INTERLACED_MERGED)) {
|
||||
if (!vc_deinterlace_ex(s->current_display_desc.color_spec,
|
||||
(unsigned char *) data, vc_get_linesize(s->current_display_desc.width, s->current_display_desc.color_spec),
|
||||
(unsigned char *) data, vc_get_linesize(s->current_display_desc.width, s->current_display_desc.color_spec),
|
||||
@@ -1170,8 +1180,8 @@ static bool display_gl_process_key(struct state_gl *s, long long int key)
|
||||
exit_uv(0);
|
||||
break;
|
||||
case 'd':
|
||||
s->deinterlace = !s->deinterlace;
|
||||
log_msg(LOG_LEVEL_NOTICE, "Deinterlacing: %s\n", s->deinterlace ? "ON" : "OFF");
|
||||
s->deinterlace = s->deinterlace == state_gl::deint::off ? state_gl::deint::on : state_gl::deint::off;
|
||||
log_msg(LOG_LEVEL_NOTICE, "Deinterlacing: %s\n", state_gl::deint_to_string(s->deinterlace));
|
||||
break;
|
||||
case 'p':
|
||||
s->paused = !s->paused;
|
||||
|
||||
@@ -119,7 +119,7 @@ struct state_sdl2 {
|
||||
SDL_Texture *texture{nullptr};
|
||||
|
||||
bool fs{false};
|
||||
bool deinterlace{false};
|
||||
enum class deint { off, on, force } deinterlace = deint::off;
|
||||
bool keep_aspect{false};
|
||||
bool vsync{true};
|
||||
bool fixed_size{false};
|
||||
@@ -150,6 +150,14 @@ struct state_sdl2 {
|
||||
~state_sdl2() {
|
||||
module_done(&mod);
|
||||
}
|
||||
static const char *deint_to_string(deint val) {
|
||||
switch (val) {
|
||||
case deint::off: return "OFF";
|
||||
case deint::on: return "ON";
|
||||
case deint::force: return "FORCE";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr array display_sdl2_keybindings{
|
||||
@@ -169,7 +177,7 @@ static void display_frame(struct state_sdl2 *s, struct video_frame *frame)
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->deinterlace) {
|
||||
if (s->deinterlace == state_sdl2::deint::off || (s->deinterlace == state_sdl2::deint::on && frame->interlacing != INTERLACED_MERGED)) {
|
||||
int pitch;
|
||||
if (codec_is_planar(frame->color_spec)) {
|
||||
pitch = frame->tiles[0].width;
|
||||
@@ -248,9 +256,9 @@ static bool display_sdl2_process_key(struct state_sdl2 *s, int64_t key)
|
||||
{
|
||||
switch (key) {
|
||||
case 'd':
|
||||
s->deinterlace = !s->deinterlace;
|
||||
s->deinterlace = s->deinterlace == state_sdl2::deint::off ? state_sdl2::deint::on : state_sdl2::deint::off;
|
||||
log_msg(LOG_LEVEL_INFO, "Deinterlacing: %s\n",
|
||||
s->deinterlace ? "ON" : "OFF");
|
||||
state_sdl2::deint_to_string(s->deinterlace));
|
||||
return true;
|
||||
case 'f':
|
||||
s->fs = !s->fs;
|
||||
@@ -358,7 +366,7 @@ static void show_help(void)
|
||||
printf("SDL options:\n");
|
||||
cout << style::bold << fg::red << "\t-d sdl" << fg::reset << "[[:fs|:d|:display=<didx>|:driver=<drv>|:novsync|:renderer=<ridx>|:nodecorate|:fixed_size[=WxH]|:window_flags=<f>|:pos=<x>,<y>|:keep-aspect]*|:help]\n" << style::reset;
|
||||
printf("\twhere:\n");
|
||||
cout << style::bold <<"\t\t d" << style::reset << " - deinterlace\n";
|
||||
cout << style::bold <<"\t\td[force]" << style::reset << " - deinterlace (force even for progresive video)\n";
|
||||
cout << style::bold <<"\t\t fs" << style::reset << " - fullscreen\n";
|
||||
cout << style::bold <<"\t\t <didx>" << style::reset << " - display index, available indices: ";
|
||||
sdl2_print_displays();
|
||||
@@ -391,6 +399,10 @@ static int display_sdl2_reconfigure(void *state, struct video_desc desc)
|
||||
{
|
||||
struct state_sdl2 *s = (struct state_sdl2 *) state;
|
||||
|
||||
if (desc.interlacing == INTERLACED_MERGED && s->deinterlace == state_sdl2::deint::off) {
|
||||
LOG(LOG_LEVEL_WARNING) << MOD_NAME "Receiving interlaced video but deinterlacing is off - suggesting toggling it on (press 'd' or pass cmdline option)\n";
|
||||
}
|
||||
|
||||
s->current_desc = desc;
|
||||
return 1;
|
||||
}
|
||||
@@ -566,8 +578,8 @@ static void *display_sdl2_init(struct module *parent, const char *fmt, unsigned
|
||||
char *tok, *save_ptr;
|
||||
while((tok = strtok_r(tmp, ":", &save_ptr)))
|
||||
{
|
||||
if (strcmp(tok, "d") == 0) {
|
||||
s->deinterlace = true;
|
||||
if (strcmp(tok, "d") == 0 || strcmp(tok, "dforce") == 0) {
|
||||
s->deinterlace = strcmp(tok, "d") == 0 ? state_sdl2::deint::on : state_sdl2::deint::off;
|
||||
} else if (strncmp(tok, "display=", strlen("display=")) == 0) {
|
||||
s->display_idx = atoi(tok + strlen("display="));
|
||||
} else if (strncmp(tok, "driver=", strlen("driver=")) == 0) {
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
|
||||
struct state_deinterlace {
|
||||
struct video_frame *out; ///< for postprocess only
|
||||
_Bool force;
|
||||
};
|
||||
|
||||
static void usage(_Bool for_postprocessor)
|
||||
@@ -66,10 +67,12 @@ static void usage(_Bool for_postprocessor)
|
||||
" by applying linear blend on interleaved odd and even "
|
||||
" fileds.\n\nUsage:\n");
|
||||
if (for_postprocessor) {
|
||||
color_printf(TBOLD(TRED("\t-p deinterlace")) " | " TBOLD(TRED("-p deinterlace_blend")) "\n");
|
||||
color_printf(TBOLD(TRED("\t-p deinterlace")) "[:options] | " TBOLD(TRED("-p deinterlace_blend")) "[:options]\n");
|
||||
} else {
|
||||
color_printf(TBOLD(TRED("\t--capture-filter deinterlace")) " -t <capture>\n");
|
||||
color_printf(TBOLD(TRED("\t--capture-filter deinterlace")) "[:options] -t <capture>\n");
|
||||
}
|
||||
color_printf("\noptions:\n"
|
||||
"\t" TBOLD("force") " - apply deinterlacing even if input is progressive\n");
|
||||
}
|
||||
|
||||
static void * deinterlace_blend_init(const char *config) {
|
||||
@@ -81,6 +84,14 @@ static void * deinterlace_blend_init(const char *config) {
|
||||
struct state_deinterlace *s = calloc(1, sizeof(struct state_deinterlace));
|
||||
assert(s != NULL);
|
||||
|
||||
if (strcmp(config, "force") == 0) {
|
||||
s->force = 1;
|
||||
} else {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unknown option: %s\n", config);
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -140,16 +151,22 @@ static struct video_frame * deinterlace_getf(void *state)
|
||||
|
||||
static bool deinterlace_postprocess(void *state, struct video_frame *in, struct video_frame *out, int req_pitch)
|
||||
{
|
||||
UNUSED(state);
|
||||
assert (req_pitch == vc_get_linesize(in->tiles[0].width, in->color_spec));
|
||||
assert (video_desc_eq(video_desc_from_frame(out), video_desc_from_frame(in)));
|
||||
assert (in->tiles[0].data_len <= vc_get_linesize(in->tiles[0].width, in->color_spec) * in->tiles[0].height);
|
||||
assert (out->tiles[0].data_len <= vc_get_linesize(in->tiles[0].width, in->color_spec) * in->tiles[0].height);
|
||||
|
||||
struct state_deinterlace *s = state;
|
||||
if (in->interlacing != INTERLACED_MERGED && !s->force) {
|
||||
memcpy(out->tiles[0].data, in->tiles[0].data, in->tiles[0].data_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!vc_deinterlace_ex(in->color_spec, (unsigned char *) in->tiles[0].data, vc_get_linesize(in->tiles[0].width, in->color_spec),
|
||||
(unsigned char *) out->tiles[0].data, vc_get_linesize(out->tiles[0].width, in->color_spec),
|
||||
in->tiles[0].height)) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot deinterlace, unsupported pixel format '%s'!\n", get_codec_name(in->color_spec));
|
||||
memcpy(out->tiles[0].data, in->tiles[0].data, in->tiles[0].data_len);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
#include "video_display.h"
|
||||
#include "vo_postprocess.h"
|
||||
|
||||
#define MOD_NAME "[double_framerate] "
|
||||
#define MOD_NAME "[temporal deint] "
|
||||
#define TIMEOUT "20ms"
|
||||
#define DFR_DEINTERLACE_IMPOSSIBLE_MSG_ID 0x27ff0a78
|
||||
|
||||
@@ -70,10 +70,16 @@ struct state_df {
|
||||
int buffer_current;
|
||||
bool deinterlace;
|
||||
bool nodelay;
|
||||
bool force;
|
||||
|
||||
std::chrono::steady_clock::time_point frame_received;
|
||||
};
|
||||
|
||||
static void print_common_opts() {
|
||||
color_printf("\t" TBOLD("force ") " - apply deinterlacing even if input is not interlaced\n");
|
||||
color_printf("\t" TBOLD("nodelay") " - do not delay the other frame to keep timing. Both frames are output in burst. May not work correctly (depends on display).\n");
|
||||
}
|
||||
|
||||
static void df_usage()
|
||||
{
|
||||
char desc[] = TBOLD("double-framerate") " is an interleaver that "
|
||||
@@ -86,17 +92,20 @@ static void df_usage()
|
||||
color_printf("\t" TBOLD(TRED("-p double_framerate") "[:d][:nodelay]") "\n");
|
||||
color_printf("\nwhere:\n");
|
||||
color_printf("\t" TBOLD("d ") " - blend the output\n");
|
||||
color_printf("\t" TBOLD("nodelay") " - do not delay the other frame to keep timing. Both frames are output in burst. May not work correctly (depends on display).\n");
|
||||
print_common_opts();
|
||||
}
|
||||
|
||||
static void * init_common(enum algo algo, const char *config) {
|
||||
bool deinterlace = false;
|
||||
bool force = false;
|
||||
bool nodelay = false;
|
||||
|
||||
if (strcmp(config, "d") == 0) {
|
||||
deinterlace = true;
|
||||
} else if (strcmp(config, "nodelay") == 0) {
|
||||
nodelay = true;
|
||||
} else if (strcmp(config, "force") == 0) {
|
||||
force = true;
|
||||
} else if (strlen(config) > 0) {
|
||||
log_msg(LOG_LEVEL_ERROR, "Unknown config: %s\n", config);
|
||||
return NULL;
|
||||
@@ -110,6 +119,7 @@ static void * init_common(enum algo algo, const char *config) {
|
||||
s->buffers[0] = s->buffers[1] = NULL;
|
||||
s->buffer_current = 0;
|
||||
s->deinterlace = deinterlace;
|
||||
s->force = force;
|
||||
s->nodelay = nodelay;
|
||||
|
||||
if (s->nodelay && commandline_params.find("decoder-drop-policy") == commandline_params.end()) {
|
||||
@@ -171,9 +181,9 @@ static int common_postprocess_reconfigure(void *state, struct video_desc desc)
|
||||
s->in->color_spec = desc.color_spec;
|
||||
s->in->fps = desc.fps;
|
||||
s->in->interlacing = desc.interlacing;
|
||||
if(desc.interlacing != INTERLACED_MERGED) {
|
||||
log_msg(LOG_LEVEL_ERROR, "[Double Framerate] Warning: %s video detected. This filter is intended "
|
||||
"mainly for interlaced merged video. The result might be incorrect.\n",
|
||||
if (desc.interlacing != INTERLACED_MERGED && !s->force) {
|
||||
log_msg(LOG_LEVEL_WARNING, MOD_NAME "Warning: %s video detected. This filter is intended "
|
||||
"mainly for interlaced merged video. Framerate will be needlessly doubled.\n",
|
||||
get_interlacing_description(desc.interlacing));
|
||||
}
|
||||
|
||||
@@ -419,16 +429,23 @@ static bool common_postprocess(void *state, struct video_frame *in, struct video
|
||||
{
|
||||
struct state_df *s = (struct state_df *) state;
|
||||
|
||||
switch (s->algo) {
|
||||
case DF:
|
||||
perform_df(s, in, out, req_pitch);
|
||||
break;
|
||||
case BOB:
|
||||
perform_bob(s, in, out, req_pitch);
|
||||
break;
|
||||
case LINEAR:
|
||||
perform_linear(s, in, out, req_pitch);
|
||||
break;
|
||||
if (s->in->interlacing == INTERLACED_MERGED || s->force) {
|
||||
switch (s->algo) {
|
||||
case DF:
|
||||
perform_df(s, in, out, req_pitch);
|
||||
break;
|
||||
case BOB:
|
||||
perform_bob(s, in, out, req_pitch);
|
||||
break;
|
||||
case LINEAR:
|
||||
perform_linear(s, in, out, req_pitch);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
s->in->tiles[0].data = s->buffers[0]; // always write to first buffer
|
||||
if (in) {
|
||||
memcpy(out->tiles[0].data, in->tiles[0].data, in->tiles[0].data_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->nodelay) {
|
||||
|
||||
Reference in New Issue
Block a user