Skip to content

Commit

Permalink
Add support for horizontal/vertical flipping
Browse files Browse the repository at this point in the history
This commit also adds rotation and flipping in the gstreamer renderer.
  • Loading branch information
dougg3 authored and FD- committed Sep 13, 2020
1 parent 5900542 commit 58b068d
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 15 deletions.
13 changes: 10 additions & 3 deletions renderers/video_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ typedef enum video_renderer_type_e {
VIDEO_RENDERER_GSTREAMER
} video_renderer_type_t;

typedef enum flip_mode_e {
FLIP_NONE,
FLIP_HORIZONTAL,
FLIP_VERTICAL,
FLIP_BOTH
} flip_mode_t;

typedef struct video_renderer_s video_renderer_t;

typedef struct video_renderer_funcs_s {
Expand All @@ -71,9 +78,9 @@ typedef struct video_renderer_s {
video_renderer_type_t type;
} video_renderer_t;

video_renderer_t *video_renderer_dummy_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation);
video_renderer_t *video_renderer_rpi_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation);
video_renderer_t *video_renderer_gstreamer_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation);
video_renderer_t *video_renderer_dummy_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation, flip_mode_t flip);
video_renderer_t *video_renderer_rpi_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation, flip_mode_t flip);
video_renderer_t *video_renderer_gstreamer_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation, flip_mode_t flip);

#ifdef __cplusplus
}
Expand Down
2 changes: 1 addition & 1 deletion renderers/video_renderer_dummy.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ typedef struct video_renderer_dummy_s {

static const video_renderer_funcs_t video_renderer_dummy_funcs;

video_renderer_t *video_renderer_dummy_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation) {
video_renderer_t *video_renderer_dummy_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation, flip_mode_t flip) {
video_renderer_dummy_t *renderer;
renderer = calloc(1, sizeof(video_renderer_dummy_t));
if (!renderer) {
Expand Down
56 changes: 53 additions & 3 deletions renderers/video_renderer_gstreamer.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <assert.h>
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <stdio.h>

typedef struct video_renderer_gstreamer_s {
video_renderer_t base;
Expand Down Expand Up @@ -51,7 +52,7 @@ static gboolean check_plugins(void)
return ret;
}

video_renderer_t *video_renderer_gstreamer_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation) {
video_renderer_t *video_renderer_gstreamer_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation, flip_mode_t flip) {
video_renderer_gstreamer_t *renderer;
GError *error = NULL;

Expand All @@ -66,9 +67,58 @@ video_renderer_t *video_renderer_gstreamer_init(logger_t *logger, background_mod

assert(check_plugins());

renderer->pipeline = gst_parse_launch("appsrc name=video_source stream-type=0 format=GST_FORMAT_TIME is-live=true !"
"queue ! decodebin ! videoconvert ! autovideosink name=video_sink sync=false", &error);
// Begin the video pipeline
GString *launch = g_string_new("appsrc name=video_source stream-type=0 format=GST_FORMAT_TIME is-live=true !"
"queue ! decodebin ! videoconvert ! ");
// Setup rotation
if (rotation != 0) {
switch (rotation)
{
case 90:
case -270:
g_string_append(launch, "videoflip method=clockwise ! ");
break;
case -90:
case 270:
g_string_append(launch, "videoflip method=counterclockwise ! ");
break;
case 180:
case -180:
g_string_append(launch, "videoflip method=rotate-180 ! ");
break;
default:
printf("Error: Rotation must be +/- 0,90,180,270\n");
g_string_free(launch, TRUE);
free(renderer);
return NULL;
}
}

// Setup flip
if (flip != FLIP_NONE) {
switch (flip)
{
case FLIP_HORIZONTAL:
g_string_append(launch, "videoflip method=horizontal-flip ! ");
break;
case FLIP_VERTICAL:
g_string_append(launch, "videoflip method=vertical-flip ! ");
break;
case FLIP_BOTH:
g_string_append(launch, "videoflip method=rotate-180 ! ");
break;
case FLIP_NONE:
default:
break;
}
}

// Finish the pipeline
g_string_append(launch, "autovideosink name=video_sink sync=false");

renderer->pipeline = gst_parse_launch(launch->str, &error);
g_assert(renderer->pipeline);
g_string_free(launch, TRUE);

renderer->appsrc = gst_bin_get_by_name(GST_BIN(renderer->pipeline), "video_source");
renderer->sink = gst_bin_get_by_name(GST_BIN(renderer->pipeline), "video_sink");
Expand Down
36 changes: 33 additions & 3 deletions renderers/video_renderer_rpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ static void omx_event_handler(void *userdata, COMPONENT_T *comp, OMX_U32 data) {
logger_log(renderer->base.logger, LOGGER_DEBUG, "Video renderer config change: %p: %d", comp, data);
}

static int video_renderer_rpi_init_decoder(video_renderer_rpi_t *renderer, int rotation) {
static int video_renderer_rpi_init_decoder(video_renderer_rpi_t *renderer, int rotation, flip_mode_t flip) {
memset(renderer->components, 0, sizeof(renderer->components));
memset(renderer->tunnels, 0, sizeof(renderer->tunnels));

Expand Down Expand Up @@ -294,6 +294,36 @@ static int video_renderer_rpi_init_decoder(video_renderer_rpi_t *renderer, int r
}
}

// Setup flipping
if (flip != FLIP_NONE) {
OMX_CONFIG_MIRRORTYPE omx_mirror;
memset(&omx_mirror, 0, sizeof(OMX_CONFIG_MIRRORTYPE));
omx_mirror.nSize = sizeof(OMX_CONFIG_MIRRORTYPE);
switch (flip) {
case FLIP_HORIZONTAL:
omx_mirror.eMirror = OMX_MirrorHorizontal;
break;
case FLIP_VERTICAL:
omx_mirror.eMirror = OMX_MirrorVertical;
break;
case FLIP_BOTH:
omx_mirror.eMirror = OMX_MirrorBoth;
break;
default:
omx_mirror.eMirror = OMX_MirrorNone;
break;
}
omx_mirror.nPortIndex = 90;
omx_mirror.nVersion.nVersion = OMX_VERSION;
OMX_ERRORTYPE error = OMX_SetConfig(ilclient_get_handle(renderer->video_renderer), OMX_IndexConfigCommonMirror,
&omx_mirror);
if (error != OMX_ErrorNone) {
printf("Error: %x\n", error);
video_renderer_rpi_destroy_decoder(renderer);
return -15;
}
}

// Set decoder format
ilclient_change_component_state(renderer->video_decoder, OMX_StateIdle);
OMX_VIDEO_PARAM_PORTFORMATTYPE format;
Expand All @@ -315,7 +345,7 @@ static int video_renderer_rpi_init_decoder(video_renderer_rpi_t *renderer, int r
return 1;
}

video_renderer_t *video_renderer_rpi_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation) {
video_renderer_t *video_renderer_rpi_init(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation, flip_mode_t flip) {
video_renderer_rpi_t *renderer;
renderer = calloc(1, sizeof(video_renderer_rpi_t));
if (!renderer) {
Expand All @@ -331,7 +361,7 @@ video_renderer_t *video_renderer_rpi_init(logger_t *logger, background_mode_t ba
renderer->first_packet_time = 0;
renderer->input_frames = 0;

if (video_renderer_rpi_init_decoder(renderer, rotation) != 1) {
if (video_renderer_rpi_init_decoder(renderer, rotation, flip) != 1) {
free(renderer);
renderer = NULL;
}
Expand Down
22 changes: 17 additions & 5 deletions rpiplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@
#define DEFAULT_LOW_LATENCY false
#define DEFAULT_DEBUG_LOG false
#define DEFAULT_ROTATE 0
#define DEFAULT_FLIP FLIP_NONE
#define DEFAULT_HW_ADDRESS { (char) 0x48, (char) 0x5d, (char) 0x60, (char) 0x7c, (char) 0xee, (char) 0x22 }

int start_server(std::vector<char> hw_addr, std::string name, background_mode_t background_mode,
audio_device_t audio_device, bool low_latency, bool debug_log, int rotation);
audio_device_t audio_device, bool low_latency, bool debug_log, int rotation,
flip_mode_t flip);

int stop_server();

typedef video_renderer_t *(*video_init_func_t)(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation);
typedef video_renderer_t *(*video_init_func_t)(logger_t *logger, background_mode_t background_mode, bool low_latency, int rotation, flip_mode_t flip);
typedef audio_renderer_t *(*audio_init_func_t)(logger_t *logger, video_renderer_t *video_renderer, audio_device_t device, bool low_latency);

typedef struct video_renderer_list_entry_s {
Expand Down Expand Up @@ -160,6 +162,7 @@ void print_info(char *name) {
printf("-n name Specify the network name of the AirPlay server\n");
printf("-b (on|auto|off) Show black background always, only during active connection, or never\n");
printf("-r (90|180|270) Specify image rotation in multiples of 90 degrees\n");
printf("-f (horiz|vert|both) Specify image flipping (horiz = horizontal, vert = vertical, both = both)\n");
printf("-l Enable low-latency mode (disables render clock)\n");
printf("-a (hdmi|analog|off) Set audio output device\n");
printf("-vr renderer Set video renderer to use. Available renderers:\n");
Expand All @@ -183,6 +186,7 @@ int main(int argc, char *argv[]) {
audio_device_t audio_device = DEFAULT_AUDIO_DEVICE;
bool low_latency = DEFAULT_LOW_LATENCY;
int rotation = DEFAULT_ROTATE;
flip_mode_t flip = DEFAULT_FLIP;
bool debug_log = DEFAULT_DEBUG_LOG;
// Default to the best available renderer
video_init_func = video_renderers[0].init_func;
Expand Down Expand Up @@ -215,6 +219,13 @@ int main(int argc, char *argv[]) {
low_latency = !low_latency;
} else if (arg == "-r") {
rotation = atoi(argv[++i]);
} else if (arg == "-f") {
if (i == argc - 1) continue;
std::string flip_type(argv[++i]);
flip = flip_type == "horiz" ? FLIP_HORIZONTAL :
flip_type == "vert" ? FLIP_VERTICAL :
flip_type == "both" ? FLIP_BOTH :
FLIP_NONE;
} else if (arg == "-d") {
debug_log = !debug_log;
} else if (arg == "-vr") {
Expand Down Expand Up @@ -249,7 +260,7 @@ int main(int argc, char *argv[]) {
parse_hw_addr(mac_address, server_hw_addr);
}

if (start_server(server_hw_addr, server_name, background, audio_device, low_latency, debug_log, rotation) != 0) {
if (start_server(server_hw_addr, server_name, background, audio_device, low_latency, debug_log, rotation, flip) != 0) {
return 1;
}

Expand Down Expand Up @@ -322,7 +333,8 @@ extern "C" void log_callback(void *cls, int level, const char *msg) {
}

int start_server(std::vector<char> hw_addr, std::string name, background_mode_t background_mode,
audio_device_t audio_device, bool low_latency, bool debug_log, int rotation) {
audio_device_t audio_device, bool low_latency, bool debug_log, int rotation,
flip_mode_t flip) {
raop_callbacks_t raop_cbs;
memset(&raop_cbs, 0, sizeof(raop_cbs));
raop_cbs.conn_init = conn_init;
Expand All @@ -348,7 +360,7 @@ int start_server(std::vector<char> hw_addr, std::string name, background_mode_t

if (low_latency) logger_log(render_logger, LOGGER_INFO, "Using low-latency mode");

if ((video_renderer = video_init_func(render_logger, background_mode, low_latency, rotation)) == NULL) {
if ((video_renderer = video_init_func(render_logger, background_mode, low_latency, rotation, flip)) == NULL) {
LOGE("Could not init video renderer");
return -1;
}
Expand Down

0 comments on commit 58b068d

Please sign in to comment.