add the -f videoflip option, modeled on flip and rotate in RPiPlay

This commit is contained in:
fduncanh
2021-08-02 18:42:22 -04:00
parent 5166d050ba
commit f0070c065d
4 changed files with 87 additions and 16 deletions

View File

@@ -4,13 +4,16 @@ project(uxplay)
set (CMAKE_CXX_STANDARD 11)
add_definitions(-DAVAHI_COMPAT_NOWARN)
if (ZOOMFIX)
add_definitions(-DX_DISPLAY_FIX)
find_package(X11 REQUIRED)
link_libraries(${X11_LIBRARIES})
include_directories(${X11_INCLUDE_DIR})
# link_directories(${X11_LIBRARIES})
endif (ZOOMFIX)
add_definitions(-DAVAHI_COMPAT_NOWARN)
add_subdirectory(lib/llhttp)
add_subdirectory(lib/playfair)
@@ -20,5 +23,5 @@ add_subdirectory(renderers)
add_executable( uxplay uxplay.cpp)
target_link_libraries ( uxplay renderers airplay ${X11_LIBRARIES})
install(PROGRAMS uxplay DESTINATION bin)
install(TARGETS uxplay RUNTIME DESTINATION bin)

View File

@@ -33,10 +33,18 @@ extern "C" {
#include "../lib/logger.h"
#include "../lib/raop_ntp.h"
typedef enum videoflip_e {
NONE,
LEFT,
RIGHT,
INVERT,
VFLIP,
HFLIP,
} videoflip_t;
typedef struct video_renderer_s video_renderer_t;
video_renderer_t *video_renderer_init(logger_t *logger, const char *server_name);
video_renderer_t *video_renderer_init(logger_t *logger, const char *server_name, videoflip_t videoflip);
void video_renderer_start(video_renderer_t *renderer);
void video_renderer_render_buffer(video_renderer_t *renderer, raop_ntp_t *ntp, unsigned char* data, int data_len, uint64_t pts, int type);
void video_renderer_flush(video_renderer_t *renderer);

View File

@@ -53,7 +53,7 @@ static gboolean check_plugins (void)
return ret;
}
video_renderer_t *video_renderer_init(logger_t *logger, const char *server_name) {
video_renderer_t *video_renderer_init(logger_t *logger, const char *server_name, videoflip_t videoflip) {
video_renderer_t *renderer;
GError *error = NULL;
@@ -71,8 +71,29 @@ video_renderer_t *video_renderer_init(logger_t *logger, const char *server_name)
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);
GString *launch = g_string_new("appsrc name=video_source stream-type=0 format=GST_FORMAT_TIME is-live=true !"
"queue ! decodebin ! videoconvert ! ");
/* image transform */
switch (videoflip) {
case LEFT:
g_string_append(launch, "videoflip method=counterclockwise ! ");
break;
case RIGHT:
g_string_append(launch, "videoflip method=clockwise ! ");
break;
case INVERT:
g_string_append(launch, "videoflip method=rotate-180 ! ");
break;
case HFLIP:
g_string_append(launch, "videoflip method=horizontal-flip ! ");
break;
case VFLIP:
g_string_append(launch, "videoflip method=vertical-flip ! ");
}
g_string_append(launch, "autovideosink name=video_sink sync=false");
renderer->pipeline = gst_parse_launch(launch->str, &error);
g_assert (renderer->pipeline);
renderer->appsrc = gst_bin_get_by_name (GST_BIN (renderer->pipeline), "video_source");

View File

@@ -44,7 +44,7 @@
int start_server(std::vector<char> hw_addr, std::string name, unsigned short display_size[2],
unsigned short tcp[2], unsigned short udp[3],
unsigned short tcp[2], unsigned short udp[3], videoflip_t videoflip,
bool use_audio, bool debug_log);
int stop_server();
@@ -120,8 +120,9 @@ void print_info(char *name) {
printf("UxPlay %s: An open-source AirPlay mirroring server based on RPiPlay\n", VERSION);
printf("Usage: %s [-n name] [-s wxh] [-p [n]]\n", name);
printf("Options:\n");
printf("-n name Specify the network name of the AirPlay server\n");
printf("-s wxh Set display size: width w height h default 1920x1080\n");
printf("-n name Specify the network name of the AirPlay server\n");
printf("-s wxh Set display size: width w height h default 1920x1080\n");
printf("-f {H|V|R|L|I} horizontal/vertical flip; rotate 90R/90L/180 deg\n");
printf("-p n Use fixed UDP+TCP network ports n:n+1:n+2 > 1023\n");
printf("-p Use legacy UDP 6000:6001:7011 TCP 7000:7001:7100\n");
printf("-r use random MAC address (use for concurrent UxPlay's)\n");
@@ -159,6 +160,33 @@ bool get_lowest_port(char *str, unsigned short *n) {
return true;
}
bool get_videoflip(char *str, videoflip_t *videoflip) {
char c = str[0];
printf(" %c |%s| %d\n",c, str, strlen(str));
if(strlen(str) > 1) return false;
printf(" %c |%s| %d\n",c, str, strlen(str));
switch (c) {
case 'L':
*videoflip = LEFT;
break;
case 'R':
*videoflip = RIGHT;
break;
case 'I':
*videoflip = INVERT;
break;
case 'H':
*videoflip = HFLIP;
break;
case 'V':
*videoflip = VFLIP;
break;
default:
return false;
}
return true;
}
int main(int argc, char *argv[]) {
init_signals();
@@ -169,7 +197,8 @@ int main(int argc, char *argv[]) {
bool debug_log = DEFAULT_DEBUG_LOG;
unsigned short display_size[2] = { (unsigned short) DEFAULT_DISPLAY_WIDTH, (unsigned short) DEFAULT_DISPLAY_HEIGHT };
unsigned short tcp[2] = {0}, udp[3] = {0};
videoflip_t videoflip = NONE;
#ifdef AVAHI_COMPAT_NOWARN
//suppress avahi_compat nag message
char avahi_compat_nowarn[] = "AVAHI_COMPAT_NOWARN==1";
@@ -187,12 +216,21 @@ int main(int argc, char *argv[]) {
fprintf(stderr,"invalid \"-s\" had no argument\n");
exit(1);
}
std::string value(argv[++i]);
std::string value(argv[++i]);
if (!get_display_size(argv[i], &display_size[0], &display_size[1])) {
fprintf(stderr, "invalid \"-s %s\"; default is \"-s 1920x1080\" (< 5 digits)\n",
value.c_str());
exit(1);
}
} else if (arg == "-f") {
if (i == argc - 1 || argv[i + 1][0] == '-') {
fprintf(stderr,"invalid \"f\" had no argument\n");
exit(1);
}
if (!get_videoflip(argv[++i], &videoflip)) {
fprintf(stderr,"invalid \"-f %s\" , unknown videoflip type\n",argv[i]);
exit(1);
}
} else if (arg == "-p") {
if (i == argc - 1 || argv[i + 1][0] == '-') {
tcp[0] = 7100; tcp[1] = 7000;
@@ -220,7 +258,7 @@ int main(int argc, char *argv[]) {
print_info(argv[0]);
exit(0);
} else {
LOGI("unknown option %s, skipping\n",argv[i]);
LOGI("unknown option %s, skipping\n",argv[i]);
}
}
@@ -237,7 +275,8 @@ int main(int argc, char *argv[]) {
parse_hw_addr(mac_address, server_hw_addr);
if (start_server(server_hw_addr, server_name, display_size, tcp, udp, use_audio, debug_log) != 0) {
if (start_server(server_hw_addr, server_name, display_size, tcp, udp, videoflip,
use_audio, debug_log) != 0) {
return 1;
}
running = true;
@@ -307,7 +346,7 @@ extern "C" void log_callback(void *cls, int level, const char *msg) {
}
int start_server(std::vector<char> hw_addr, std::string name, unsigned short display_size[2],
unsigned short tcp[2], unsigned short udp[3],
unsigned short tcp[2], unsigned short udp[3], videoflip_t videoflip,
bool use_audio, bool debug_log) {
raop_callbacks_t raop_cbs;
memset(&raop_cbs, 0, sizeof(raop_cbs));
@@ -332,7 +371,7 @@ int start_server(std::vector<char> hw_addr, std::string name, unsigned short dis
logger_set_callback(render_logger, log_callback, NULL);
logger_set_level(render_logger, debug_log ? LOGGER_DEBUG : LOGGER_INFO);
if ((video_renderer = video_renderer_init(render_logger, name.c_str())) == NULL) {
if ((video_renderer = video_renderer_init(render_logger, name.c_str(), videoflip)) == NULL) {
LOGE("Could not init video renderer");
return -1;
}
@@ -351,7 +390,7 @@ int start_server(std::vector<char> hw_addr, std::string name, unsigned short dis
/* write desired display pixel width, pixel height to raop (use 0 for default values) */
raop_set_display_size(raop, display_size[0], display_size[1]);
/* network port selection (use value 0 for dynamic assignment) */
/* network port selection (ports listed as "0" will dynamically assigned) */
raop_set_tcp_ports(raop, tcp);
raop_set_udp_ports(raop, udp);