mirror of
https://github.com/albfan/miraclecast.git
synced 2025-03-09 23:38:56 +00:00
integrate miracle-sender with miracast-srcctl
This commit is contained in:
parent
8a935e1893
commit
047775303b
6 changed files with 370 additions and 182 deletions
|
@ -94,7 +94,7 @@ static void src_handle_setup(struct ctl_src *s,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buf[128];
|
char buf[256];
|
||||||
snprintf(buf, sizeof(buf), "RTP/AVP/UDP;unicast;client_port=%d", s->sink.rtp_ports.port0);
|
snprintf(buf, sizeof(buf), "RTP/AVP/UDP;unicast;client_port=%d", s->sink.rtp_ports.port0);
|
||||||
r = rtsp_message_append(rep, "<s>",
|
r = rtsp_message_append(rep, "<s>",
|
||||||
"Transport", buf);
|
"Transport", buf);
|
||||||
|
@ -181,6 +181,8 @@ static void src_handle_play(struct ctl_src *s,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctl_fn_src_playing(s);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -518,27 +520,6 @@ error:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int src_set_format(struct ctl_src *s,
|
|
||||||
unsigned int cea_res,
|
|
||||||
unsigned int vesa_res,
|
|
||||||
unsigned int hh_res)
|
|
||||||
{
|
|
||||||
int hres, vres;
|
|
||||||
|
|
||||||
// if ((vfd_get_cea_resolution(cea_res, &hres, &vres) == 0) ||
|
|
||||||
// (vfd_get_vesa_resolution(vesa_res, &hres, &vres) == 0) ||
|
|
||||||
// (vfd_get_hh_resolution(hh_res, &hres, &vres) == 0)) {
|
|
||||||
// if (hres && vres) {
|
|
||||||
// s->hres = hres;
|
|
||||||
// s->vres = vres;
|
|
||||||
// ctl_fn_sink_resolution_set(s);
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void src_handle(struct ctl_src *s,
|
static void src_handle(struct ctl_src *s,
|
||||||
struct rtsp_message *m)
|
struct rtsp_message *m)
|
||||||
{
|
{
|
||||||
|
@ -634,7 +615,7 @@ static void src_connected(struct ctl_src *s)
|
||||||
sd_event_source_set_enabled(s->fd_source, SD_EVENT_OFF);
|
sd_event_source_set_enabled(s->fd_source, SD_EVENT_OFF);
|
||||||
|
|
||||||
len = sizeof(addr);
|
len = sizeof(addr);
|
||||||
int fd = accept(s->fd, (struct sockaddr *) &addr, &len);
|
int fd = accept4(s->fd, (struct sockaddr *) &addr, &len, SOCK_CLOEXEC);
|
||||||
|
|
||||||
r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len);
|
r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* vim: set tabstop=4:softtabstop=4:shiftwidth=4:noexpandtab
|
|
||||||
*
|
|
||||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||||
*
|
*
|
||||||
* MiracleCast is free software; you can redistribute it and/or modify it
|
* MiracleCast is free software; you can redistribute it and/or modify it
|
||||||
|
@ -82,8 +80,6 @@ struct ctl_src {
|
||||||
char *local;
|
char *local;
|
||||||
char *session;
|
char *session;
|
||||||
char url[256];
|
char url[256];
|
||||||
// char *uibc_config;
|
|
||||||
// char *uibc_setting;
|
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
size_t addr_size;
|
size_t addr_size;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
|
@ -253,6 +253,7 @@ void ctl_fn_peer_disconnected(struct ctl_peer *p);
|
||||||
void ctl_fn_link_new(struct ctl_link *l);
|
void ctl_fn_link_new(struct ctl_link *l);
|
||||||
void ctl_fn_link_free(struct ctl_link *l);
|
void ctl_fn_link_free(struct ctl_link *l);
|
||||||
|
|
||||||
|
void ctl_fn_src_playing(struct ctl_src *s);
|
||||||
void ctl_fn_src_connected(struct ctl_src *s);
|
void ctl_fn_src_connected(struct ctl_src *s);
|
||||||
void ctl_fn_src_disconnected(struct ctl_src *s);
|
void ctl_fn_src_disconnected(struct ctl_src *s);
|
||||||
|
|
||||||
|
|
198
src/ctl/srcctl.c
198
src/ctl/srcctl.c
|
@ -33,8 +33,11 @@
|
||||||
#include <systemd/sd-journal.h>
|
#include <systemd/sd-journal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include "ctl.h"
|
#include "ctl.h"
|
||||||
//#include "ctl-sink.h"
|
#include "ctl-src.h"
|
||||||
#include "wfd.h"
|
#include "wfd.h"
|
||||||
#include "shl_macro.h"
|
#include "shl_macro.h"
|
||||||
#include "shl_util.h"
|
#include "shl_util.h"
|
||||||
|
@ -47,12 +50,14 @@ static sd_event_source *scan_timeout;
|
||||||
static sd_event_source *src_timeout;
|
static sd_event_source *src_timeout;
|
||||||
static unsigned int src_timeout_time;
|
static unsigned int src_timeout_time;
|
||||||
static bool src_connected;
|
static bool src_connected;
|
||||||
//static pid_t sink_pid;
|
static pid_t src_pid;
|
||||||
//
|
|
||||||
//static char *selected_ link;
|
//static char *selected_ link;
|
||||||
static struct ctl_link *running_link;
|
static struct ctl_link *running_link;
|
||||||
static struct ctl_peer *running_peer;
|
static struct ctl_peer *running_peer;
|
||||||
static struct ctl_peer *pending_peer;
|
static struct ctl_peer *pending_peer;
|
||||||
|
|
||||||
|
void launch_sender(struct ctl_src *s);
|
||||||
//
|
//
|
||||||
//char *gst_scale_res;
|
//char *gst_scale_res;
|
||||||
int gst_audio_en = 1;
|
int gst_audio_en = 1;
|
||||||
|
@ -452,109 +457,81 @@ static const struct cli_cmd cli_cmds[] = {
|
||||||
{ "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help" },
|
{ "help", NULL, CLI_M, CLI_MORE, 0, NULL, "Print help" },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
//
|
|
||||||
//static void spawn_gst(struct ctl_sink *s)
|
static void spawn_gst(struct ctl_src *s)
|
||||||
//{
|
{
|
||||||
// pid_t pid;
|
pid_t pid;
|
||||||
// int fd_journal;
|
int fd_journal;
|
||||||
// sigset_t mask;
|
sigset_t mask;
|
||||||
//
|
|
||||||
// if (sink_pid > 0)
|
if (src_pid > 0)
|
||||||
// return;
|
return;
|
||||||
//
|
|
||||||
// pid = fork();
|
pid = fork();
|
||||||
// if (pid < 0) {
|
if (pid < 0) {
|
||||||
// return cli_vERRNO();
|
return cli_vERRNO();
|
||||||
// } else if (!pid) {
|
} else if (!pid) {
|
||||||
// /* child */
|
/* child */
|
||||||
//
|
|
||||||
// sigemptyset(&mask);
|
sigemptyset(&mask);
|
||||||
// sigprocmask(SIG_SETMASK, &mask, NULL);
|
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||||
//
|
|
||||||
// /* redirect stdout/stderr to journal */
|
/* redirect stdout/stderr to journal */
|
||||||
// fd_journal = sd_journal_stream_fd("miracle-sinkctl-gst",
|
fd_journal = sd_journal_stream_fd("miracle-srcctl-gst",
|
||||||
// LOG_DEBUG,
|
LOG_DEBUG,
|
||||||
// false);
|
false);
|
||||||
// if (fd_journal >= 0) {
|
if (fd_journal >= 0) {
|
||||||
// /* dup journal-fd to stdout and stderr */
|
/* dup journal-fd to stdout and stderr */
|
||||||
// dup2(fd_journal, 1);
|
dup2(fd_journal, 1);
|
||||||
// dup2(fd_journal, 2);
|
dup2(fd_journal, 2);
|
||||||
// } else {
|
} else {
|
||||||
// /* no journal? redirect stdout to parent's stderr */
|
/* no journal? redirect stdout to parent's stderr */
|
||||||
// dup2(2, 1);
|
dup2(2, 1);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// launch_player(s);
|
launch_sender(s);
|
||||||
// _exit(1);
|
_exit(1);
|
||||||
// } else {
|
} else {
|
||||||
// sink_pid = pid;
|
src_pid = pid;
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//void launch_player(struct ctl_sink *s) {
|
void launch_sender(struct ctl_src *s) {
|
||||||
// char *argv[64];
|
char * argv[64];
|
||||||
// char resolution[64];
|
char resolution[64];
|
||||||
// char port[64];
|
char port[64];
|
||||||
// char uibc_portStr[64];
|
char uibc_portStr[64];
|
||||||
// int i = 0;
|
int i = 0;
|
||||||
// char* player;
|
|
||||||
// if (uibc) {
|
argv[i++] = "miracle-sender";
|
||||||
// player = "uibc-viewer";
|
//if (gst_audio_en) {
|
||||||
// } else {
|
// argv[i++] = "--acodec";
|
||||||
// player = "miracle-gst";
|
// argv[i++] = "aac";
|
||||||
// }
|
//}
|
||||||
//
|
argv[i++] = "--host";
|
||||||
// argv[i++] = player;
|
argv[i++] = inet_ntoa(((struct sockaddr_in *) &s->addr)->sin_addr);
|
||||||
// if (uibc) {
|
argv[i++] = "-p";
|
||||||
// argv[i++] = s->target;
|
sprintf(port, "%d", rstp_port);
|
||||||
// sprintf(uibc_portStr, "%d", uibc_port);
|
argv[i++] = port;
|
||||||
// argv[i++] = uibc_portStr;
|
|
||||||
// }
|
|
||||||
// if (cli_max_sev >= 7)
|
|
||||||
// argv[i++] = "-d 3";
|
|
||||||
// if (gst_audio_en)
|
|
||||||
// argv[i++] = "-a";
|
|
||||||
// if (gst_scale_res) {
|
|
||||||
// argv[i++] = "-s";
|
|
||||||
// argv[i++] = gst_scale_res;
|
|
||||||
// }
|
|
||||||
// argv[i++] = "-p";
|
|
||||||
// sprintf(port, "%d", rstp_port);
|
|
||||||
// argv[i++] = port;
|
|
||||||
//
|
|
||||||
// if (s->hres && s->vres) {
|
// if (s->hres && s->vres) {
|
||||||
// sprintf(resolution, "%dx%d", s->hres, s->vres);
|
// sprintf(resolution, "%dx%d", s->hres, s->vres);
|
||||||
// argv[i++] = "-r";
|
// argv[i++] = "-r";
|
||||||
// argv[i++] = resolution;
|
// argv[i++] = resolution;
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// argv[i] = NULL;
|
argv[i] = NULL;
|
||||||
//
|
|
||||||
// i = 0;
|
if (execvpe(argv[0], argv, environ) < 0) {
|
||||||
// int size = 0;
|
cli_debug("stream sender failed (%d): %m", errno);
|
||||||
// while (argv[i]) {
|
int i = 0;
|
||||||
// size += strlen(argv[i++] + 1);
|
cli_debug("printing environment: ");
|
||||||
// }
|
while (environ[i]) {
|
||||||
//
|
cli_debug("%s", environ[i++]);
|
||||||
// char* player_command = malloc(size);
|
}
|
||||||
// i = 0;
|
}
|
||||||
// strcpy(player_command, argv[i++]);
|
}
|
||||||
// while (argv[i]) {
|
|
||||||
// strcat(player_command, " ");
|
|
||||||
// strcat(player_command, argv[i++]);
|
|
||||||
// }
|
|
||||||
// log_debug("player command: %s", player_command);
|
|
||||||
// //free(player_command);
|
|
||||||
// if (execvpe(argv[0], argv, environ) < 0) {
|
|
||||||
// cli_debug("stream player failed (%d): %m", errno);
|
|
||||||
// int i = 0;
|
|
||||||
// cli_debug("printing environment: ");
|
|
||||||
// while (environ[i]) {
|
|
||||||
// cli_debug("%s", environ[i++]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//void launch_uibc_daemon(int port) {
|
//void launch_uibc_daemon(int port) {
|
||||||
// char *argv[64];
|
// char *argv[64];
|
||||||
// char portStr[64];
|
// char portStr[64];
|
||||||
|
@ -571,11 +548,11 @@ static const struct cli_cmd cli_cmds[] = {
|
||||||
//
|
//
|
||||||
//static void kill_gst(void)
|
//static void kill_gst(void)
|
||||||
//{
|
//{
|
||||||
// if (sink_pid <= 0)
|
// if (src_pid <= 0)
|
||||||
// return;
|
// return;
|
||||||
//
|
//
|
||||||
// kill(sink_pid, SIGTERM);
|
// kill(src_pid, SIGTERM);
|
||||||
// sink_pid = 0;
|
// src_pid = 0;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void ctl_fn_src_connected(struct ctl_src *s)
|
void ctl_fn_src_connected(struct ctl_src *s)
|
||||||
|
@ -595,12 +572,13 @@ void ctl_fn_src_disconnected(struct ctl_src *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//void ctl_fn_sink_resolution_set(struct ctl_sink *s)
|
void ctl_fn_src_playing(struct ctl_src *s)
|
||||||
//{
|
{
|
||||||
// cli_printf("SINK set resolution %dx%d\n", s->hres, s->vres);
|
cli_printf("SRC got play request\n");
|
||||||
// if (sink_connected)
|
// TODO src_connected must be true, why if() failed?
|
||||||
// spawn_gst(s);
|
//if (src_connected)
|
||||||
//}
|
spawn_gst(s);
|
||||||
|
}
|
||||||
|
|
||||||
void ctl_fn_peer_new(struct ctl_peer *p)
|
void ctl_fn_peer_new(struct ctl_peer *p)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
pkg_check_modules(GTK REQUIRED gtk+-3.0)
|
||||||
pkg_check_modules(GST REQUIRED gstreamer-1.0)
|
pkg_check_modules(GST REQUIRED gstreamer-1.0)
|
||||||
pkg_check_modules(GST_PBUTILS REQUIRED gstreamer-pbutils-1.0)
|
pkg_check_modules(GST_PBUTILS REQUIRED gstreamer-pbutils-1.0)
|
||||||
|
|
||||||
include_directories(${GST_INCLUDE_DIRS} ${GST_PBUTILS_INCLUDE_DIRS})
|
include_directories(
|
||||||
|
${GTK_INCLUDE_DIRS}
|
||||||
|
${GST_INCLUDE_DIRS}
|
||||||
|
${GST_PBUTILS_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(miracle-sender sender)
|
add_executable(miracle-sender sender)
|
||||||
|
|
||||||
target_link_libraries(miracle-sender ${GST_LIBRARIES} ${GST_PBUTILS_LIBRARIES})
|
target_link_libraries(
|
||||||
|
miracle-sender
|
||||||
|
${GTK_LIBRARIES}
|
||||||
|
${GST_LIBRARIES}
|
||||||
|
${GST_PBUTILS_LIBRARIES})
|
||||||
|
|
||||||
install(TARGETS miracle-sender DESTINATION bin)
|
install(TARGETS miracle-sender DESTINATION bin)
|
||||||
|
|
|
@ -1,86 +1,309 @@
|
||||||
/*
|
/*
|
||||||
* =====================================================================================
|
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||||
*
|
*
|
||||||
* Filename: sender.c
|
* MiracleCast is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* Description:
|
* MiracleCast is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* Version: 1.0
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* Created: 2016年10月17日 18時11分16秒
|
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||||
* Revision: none
|
|
||||||
* Compiler: gcc
|
|
||||||
*
|
|
||||||
* Author: YOUR NAME (),
|
|
||||||
* Organization:
|
|
||||||
*
|
|
||||||
* =====================================================================================
|
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <string.h>
|
||||||
|
#include <glib.h>
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
#include <glib/gprintf.h>
|
||||||
|
#include <gdk/gdk.h>
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/pbutils/pbutils.h>
|
#include <gst/pbutils/pbutils.h>
|
||||||
#include <gst/pbutils/encoding-profile.h>
|
#include <gst/pbutils/encoding-profile.h>
|
||||||
|
|
||||||
int main(int argc, char *args[])
|
struct CmdChannel
|
||||||
|
{
|
||||||
|
gint in;
|
||||||
|
gint out;
|
||||||
|
|
||||||
|
guint in_source;
|
||||||
|
|
||||||
|
gboolean controllee;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean on_req_in(gint fd, GIOCondition cond, struct CmdChannel *self)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct CmdChannel * cmd_channel_new()
|
||||||
|
{
|
||||||
|
int fds[2];
|
||||||
|
GError *error = NULL;
|
||||||
|
struct CmdChannel *self = g_slice_new(struct CmdChannel);
|
||||||
|
if(!self) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!g_unix_open_pipe(fds, 0, &error)) {
|
||||||
|
g_warning("%s", error->message);
|
||||||
|
goto free_self;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->in = fds[0];
|
||||||
|
self->out = fds[1];
|
||||||
|
|
||||||
|
self->in_source = g_unix_fd_add(self->in,
|
||||||
|
G_IO_IN | G_IO_ERR | G_IO_HUP,
|
||||||
|
(GUnixFDSourceFunc) on_req_in,
|
||||||
|
self);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
free_self:
|
||||||
|
g_slice_free(struct CmdChannel, self);
|
||||||
|
self = NULL;
|
||||||
|
end:
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_channel_free(struct CmdChannel *self)
|
||||||
|
{
|
||||||
|
g_source_remove(self->in_source);
|
||||||
|
g_close(self->in, NULL);
|
||||||
|
g_close(self->out, NULL);
|
||||||
|
g_slice_free(struct CmdChannel, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Sender
|
||||||
{
|
{
|
||||||
GMainLoop *loop;
|
GMainLoop *loop;
|
||||||
|
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
|
|
||||||
|
struct CmdChannel *channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gchar *arg_host = NULL;
|
||||||
|
|
||||||
|
static guint arg_port = 1991;
|
||||||
|
|
||||||
|
static guint arg_width = 0;
|
||||||
|
|
||||||
|
static guint arg_height = 0;
|
||||||
|
|
||||||
|
static gint arg_screen = -1;
|
||||||
|
|
||||||
|
static gchar *arg_acodec = NULL;
|
||||||
|
|
||||||
|
static struct Sender *sender_new()
|
||||||
|
{
|
||||||
|
struct Sender *self = g_slice_new(struct Sender);
|
||||||
|
if(!self) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sender_free(struct Sender *self)
|
||||||
|
{
|
||||||
|
if(self->pipeline) {
|
||||||
|
gst_element_set_state(self->pipeline, GST_STATE_NULL);
|
||||||
|
g_object_unref(G_OBJECT(self->pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self->loop) {
|
||||||
|
g_main_loop_unref(self->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slice_free(struct Sender, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sender_prepare(struct Sender *self)
|
||||||
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
GString *desc = g_string_new("ximagesrc ");
|
||||||
|
GstElement *encoder;
|
||||||
|
GstElement *vconv;
|
||||||
|
gint screen_no;
|
||||||
|
|
||||||
gst_init(&argc, &args);
|
if(arg_screen == -1) {
|
||||||
gst_pb_utils_init();
|
GdkScreen *screen = gdk_screen_get_default();
|
||||||
|
screen_no = gdk_screen_get_number(screen);
|
||||||
GString *desc = g_string_new("");
|
}
|
||||||
|
else {
|
||||||
|
screen_no = arg_screen;
|
||||||
|
}
|
||||||
g_string_append_printf(desc,
|
g_string_append_printf(desc,
|
||||||
"ximagesrc "
|
"screen-num=%d ! video/x-raw, framerate=30/1 ",
|
||||||
"! videoscale "
|
screen_no);
|
||||||
"! video/x-raw, width=%d, height=%d, framerate=%d/1 "
|
|
||||||
"! videoconvert name=vconverter "
|
if(arg_width || arg_height) {
|
||||||
|
g_string_append(desc, "! videoscale ! video/x-raw, ");
|
||||||
|
}
|
||||||
|
if(arg_width) {
|
||||||
|
g_string_append_printf(desc, "width=%d ", arg_width);
|
||||||
|
}
|
||||||
|
if(arg_height) {
|
||||||
|
g_string_append_printf(desc, "height=%d ", arg_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_string_append_printf(desc,
|
||||||
|
"! videoconvert name=vconv "
|
||||||
"! video/x-raw, format=NV12 "
|
"! video/x-raw, format=NV12 "
|
||||||
"! encodebin name=encoder "
|
"! encodebin name=encoder "
|
||||||
"! rtpmp2tpay "
|
"! rtpmp2tpay "
|
||||||
"! udpsink host=%s port=%d ",
|
"! udpsink host=\"%s\" port=%d ",
|
||||||
1280, 720, 30,
|
arg_host,
|
||||||
"127.0.0.1",
|
arg_port);
|
||||||
1991);
|
|
||||||
|
|
||||||
pipeline = gst_parse_launch(desc->str, &error);
|
if(arg_acodec) {
|
||||||
|
g_string_append_printf(desc, "pulsesrc device=\"%s\" ! encoder.",
|
||||||
|
"alsa_output.pci-0000_00_1b.0.analog-stereo");
|
||||||
|
}
|
||||||
|
|
||||||
|
g_info("final pipeline: %s", desc->str);
|
||||||
|
|
||||||
|
self->pipeline = gst_parse_launch(desc->str, &error);
|
||||||
if(GST_PARSE_ERROR_LINK != error->code) {
|
if(GST_PARSE_ERROR_LINK != error->code) {
|
||||||
g_error("%s", error->message);
|
g_error("%s", error->message);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstCaps *caps = gst_caps_from_string("video/mpegts, systemstream=true, packetsize=188");
|
GstCaps *caps = gst_caps_from_string("video/mpegts, systemstream=true, packetsize=188");
|
||||||
GstEncodingContainerProfile *container = gst_encoding_container_profile_new("mpeg-ts-profile",
|
GstEncodingContainerProfile *cprofile = gst_encoding_container_profile_new("mpeg-ts-profile",
|
||||||
NULL,
|
NULL,
|
||||||
caps,
|
caps,
|
||||||
NULL);
|
NULL);
|
||||||
gst_caps_unref(caps);
|
gst_caps_unref(caps);
|
||||||
|
|
||||||
caps = gst_caps_from_string("video/x-h264, format=YV12, width=1280, height=720");
|
caps = gst_caps_from_string("video/x-h264, format=YV12, width=1280, height=720");
|
||||||
GstEncodingVideoProfile *vencoder = gst_encoding_video_profile_new(caps, NULL, NULL, 0);
|
GstEncodingVideoProfile *vprofile = gst_encoding_video_profile_new(caps, NULL, NULL, 0);
|
||||||
gst_caps_unref(caps);
|
gst_encoding_container_profile_add_profile(cprofile, GST_ENCODING_PROFILE(vprofile));
|
||||||
|
//gst_caps_unref(caps);
|
||||||
|
/*g_object_unref(vprofile);*/
|
||||||
|
|
||||||
gst_encoding_container_profile_add_profile(container, GST_ENCODING_PROFILE(vencoder));
|
if(arg_acodec) {
|
||||||
/*g_object_unref(vencoder);*/
|
if(!strcmp("aac", arg_acodec)) {
|
||||||
|
caps = gst_caps_from_string("audio/aac");
|
||||||
|
}
|
||||||
|
GstEncodingAudioProfile *aprofile = gst_encoding_audio_profile_new(caps, NULL, NULL, 0);
|
||||||
|
//gst_caps_unref(caps);
|
||||||
|
|
||||||
GstElement *encoder = gst_bin_get_by_name(GST_BIN(pipeline), "encoder");
|
gst_encoding_container_profile_add_profile(cprofile, GST_ENCODING_PROFILE(aprofile));
|
||||||
g_object_set(G_OBJECT(encoder), "profile", container, NULL);
|
/*g_object_unref(aprofile);*/
|
||||||
/*g_object_unref(container);*/
|
|
||||||
|
|
||||||
GstElement *vconverter = gst_bin_get_by_name(GST_BIN(pipeline), "vconverter");
|
|
||||||
if(!gst_element_link(vconverter, encoder)) {
|
|
||||||
printf("failed to link vconverter to encoder\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
encoder = gst_bin_get_by_name(GST_BIN(self->pipeline), "encoder");
|
||||||
|
g_object_set(G_OBJECT(encoder), "profile", cprofile, NULL);
|
||||||
|
/*g_object_unref(cprofile);*/
|
||||||
|
|
||||||
loop = g_main_loop_new(NULL, FALSE);
|
vconv = gst_bin_get_by_name(GST_BIN(self->pipeline), "vconv");
|
||||||
g_main_loop_run(loop);
|
if(!gst_element_link(vconv, encoder)) {
|
||||||
|
printf("failed to link vconv to encoder\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
self->loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
g_object_unref(pipeline);
|
if(self->pipeline) {
|
||||||
|
g_object_unref(self->pipeline);
|
||||||
|
self->pipeline = NULL;
|
||||||
|
}
|
||||||
end:
|
end:
|
||||||
|
g_string_free(desc, TRUE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sender_start(struct Sender *self)
|
||||||
|
{
|
||||||
|
gst_element_set_state(self->pipeline, GST_STATE_PLAYING);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sender_pause(struct Sender *self)
|
||||||
|
{
|
||||||
|
gst_element_set_state(self->pipeline, GST_STATE_PAUSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sender_stop(struct Sender *self)
|
||||||
|
{
|
||||||
|
gst_element_set_state(self->pipeline, GST_STATE_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sender_run(struct Sender *self)
|
||||||
|
{
|
||||||
|
g_main_loop_run(self->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arg_enable_audio();
|
||||||
|
|
||||||
|
static GOptionEntry entries[] = {
|
||||||
|
{ "host", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &arg_host, "the hostname of sink", "" },
|
||||||
|
{ "port", 'p', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_port, "the port which sink is waiting for RTP string", "" },
|
||||||
|
{ "width", 'w', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_width, "", "" },
|
||||||
|
{ "height", 'h', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_height, "", "" },
|
||||||
|
{ "screen-num", 's', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &arg_screen, "screen number to cast to", "" },
|
||||||
|
{ "acodec", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &arg_acodec, "codec to encode audio", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void arg_parse(int *argc, char ***args)
|
||||||
|
{
|
||||||
|
GOptionContext *opt_context;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
opt_context = g_option_context_new("");
|
||||||
|
if(!opt_context) {
|
||||||
|
g_error("%s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_option_context_add_main_entries(opt_context, entries, NULL);
|
||||||
|
if(!g_option_context_parse(opt_context, argc, args, &error)) {
|
||||||
|
g_fprintf(stderr, "%s\n", error->message);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0 >= arg_port || arg_port > 65535) {
|
||||||
|
g_fprintf(stderr, "Invalid port number: %i\n", arg_port);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_option_context_free(opt_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *args[])
|
||||||
|
{
|
||||||
|
struct Sender *sender;
|
||||||
|
|
||||||
|
arg_parse(&argc, &args);
|
||||||
|
|
||||||
|
gdk_init(&argc, &args);
|
||||||
|
gst_init(&argc, &args);
|
||||||
|
gst_pb_utils_init();
|
||||||
|
|
||||||
|
sender = sender_new();
|
||||||
|
if(!sender) {
|
||||||
|
g_error("%s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sender_prepare(sender) < 0) {
|
||||||
|
g_error("%s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
sender_start(sender);
|
||||||
|
|
||||||
|
sender_run(sender);
|
||||||
|
|
||||||
|
sender_free(sender);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue