mirror of
https://github.com/albfan/miraclecast.git
synced 2025-02-15 04:42:06 +00:00
miracle-disp: extracting encoder, part1
Change-Id: Ic9293e9cf379d352c75701834f17fa553f0bf52d
This commit is contained in:
parent
8aacea933d
commit
6719f8795b
7 changed files with 562 additions and 279 deletions
|
@ -516,7 +516,8 @@ private class WfdCtl : GLib.Application
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Error error = null;
|
Error error = null;
|
||||||
uint id = Timeout.add_seconds(10, () => {
|
var timeout_src = new TimeoutSource(10);
|
||||||
|
timeout_src.set_callback(() => {
|
||||||
error = new WfdCtlError.TIMEOUT("failed to establish session");
|
error = new WfdCtlError.TIMEOUT("failed to establish session");
|
||||||
Idle.add(establish_session.callback);
|
Idle.add(establish_session.callback);
|
||||||
return false;
|
return false;
|
||||||
|
@ -524,7 +525,7 @@ private class WfdCtl : GLib.Application
|
||||||
|
|
||||||
yield;
|
yield;
|
||||||
|
|
||||||
Source.remove(id);
|
timeout_src.destroy();
|
||||||
if(null != error) {
|
if(null != error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
169
res/gstencoder.vala
Normal file
169
res/gstencoder.vala
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
public enum GstEncoderConfig
|
||||||
|
{
|
||||||
|
DISPLAY_SYSTEM, /* string */
|
||||||
|
DISPLAY_NAME, /* string */
|
||||||
|
MONITOR, /* uint32 */
|
||||||
|
TOP, /* uint32 */
|
||||||
|
LEFT, /* uint32 */
|
||||||
|
WIDTH, /* uint32 */
|
||||||
|
HEIGHT, /* uint32 */
|
||||||
|
WINDOW_ID, /* uint32 */
|
||||||
|
FRAMERATE, /* uint32 */
|
||||||
|
SCALE_WIDTH, /* uint32 */
|
||||||
|
SCALE_HEIGHT, /* uint32 */
|
||||||
|
RTP_PORT1, /* uint32 */
|
||||||
|
RTP_PORT2, /* uint32 */
|
||||||
|
RTCP_PORT, /* uint32 */
|
||||||
|
H264_PROFILE,
|
||||||
|
H264_LEVEL,
|
||||||
|
DEBUG_LEVEL,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DBus (name = "org.freedesktop.miracle.encoder.error")]
|
||||||
|
public errordomain GstEncoderError
|
||||||
|
{
|
||||||
|
UNEXPECTED_EOS,
|
||||||
|
ENCODER_ERROR,
|
||||||
|
INVALID_STATE,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DBus(name = "org.freedesktop.miracle.encoder")]
|
||||||
|
public interface GstEncoder : GLib.Object
|
||||||
|
{
|
||||||
|
public enum State
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
CONFIGURED,
|
||||||
|
READY,
|
||||||
|
STARTED,
|
||||||
|
PAUSED,
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string OBJECT_PATH = "/org/freedesktop/miracle/encoder";
|
||||||
|
|
||||||
|
public abstract State state { get; protected set; default = State.NULL; }
|
||||||
|
|
||||||
|
public abstract void configure(HashTable<GstEncoderConfig, Variant> configs) throws GstEncoderError;
|
||||||
|
public abstract void start() throws GstEncoderError;
|
||||||
|
public abstract void pause() throws GstEncoderError;
|
||||||
|
public abstract void stop() throws GstEncoderError;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class EncoderImpl : GstEncoder, GLib.Object
|
||||||
|
{
|
||||||
|
private DBusConnection conn;
|
||||||
|
private HashTable<GstEncoderConfig, Variant> configs;
|
||||||
|
private Gst.Element pipeline;
|
||||||
|
private Gst.State pipeline_state = Gst.State.NULL;
|
||||||
|
|
||||||
|
public GstEncoder.State state { get; private set; }
|
||||||
|
|
||||||
|
public void configure(HashTable<GstEncoderConfig, Variant> configs) throws GstEncoderError
|
||||||
|
{
|
||||||
|
if(GstEncoder.State.NULL != state) {
|
||||||
|
throw new GstEncoderError.INVALID_STATE("already configured");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pipeline = Gst.parse_launch("""videotestsrc ! autovideosink""");
|
||||||
|
}
|
||||||
|
catch(Error e) {
|
||||||
|
throw new GstEncoderError.ENCODER_ERROR("%s", e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline.set_state(Gst.State.READY);
|
||||||
|
var bus = pipeline.get_bus();
|
||||||
|
bus.add_signal_watch();
|
||||||
|
bus.message.connect(on_pipeline_message);
|
||||||
|
|
||||||
|
this.configs = configs;
|
||||||
|
state = GstEncoder.State.CONFIGURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() throws GstEncoderError
|
||||||
|
{
|
||||||
|
check_configs();
|
||||||
|
|
||||||
|
pipeline.set_state(Gst.State.PLAYING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pause() throws GstEncoderError
|
||||||
|
{
|
||||||
|
check_configs();
|
||||||
|
|
||||||
|
pipeline.set_state(Gst.State.PAUSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() throws GstEncoderError
|
||||||
|
{
|
||||||
|
if(null == pipeline) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline.set_state(Gst.State.NULL);
|
||||||
|
pipeline = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void prepare() throws Error
|
||||||
|
{
|
||||||
|
conn = yield Bus.get(BusType.SESSION);
|
||||||
|
conn.register_object(GstEncoder.OBJECT_PATH, this as GstEncoder);
|
||||||
|
|
||||||
|
/* we are ready, tell parent how to communicate with us */
|
||||||
|
stderr.printf("\nunique-name: %s\n", conn.unique_name);
|
||||||
|
stderr.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check_configs() throws GstEncoderError
|
||||||
|
{
|
||||||
|
if(null == configs || null == pipeline) {
|
||||||
|
throw new GstEncoderError.INVALID_STATE("not configure yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void on_pipeline_message(Gst.Message m)
|
||||||
|
{
|
||||||
|
if(m.src != pipeline) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(m.type) {
|
||||||
|
case Gst.MessageType.EOS:
|
||||||
|
break;
|
||||||
|
case Gst.MessageType.STATE_CHANGED:
|
||||||
|
Gst.State oldstate;
|
||||||
|
m.parse_state_changed(out oldstate, out pipeline_state, null);
|
||||||
|
debug("state chagned from %s to %s",
|
||||||
|
oldstate.to_string(),
|
||||||
|
pipeline_state.to_string());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
debug("unhandled message: %s", m.type.to_string());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MainLoop loop;
|
||||||
|
|
||||||
|
int main(string[] argv)
|
||||||
|
{
|
||||||
|
Gst.init(ref argv);
|
||||||
|
|
||||||
|
var encoder = new EncoderImpl();
|
||||||
|
encoder.prepare.begin((o, r) => {
|
||||||
|
try {
|
||||||
|
encoder.prepare.end(r);
|
||||||
|
}
|
||||||
|
catch(Error e) {
|
||||||
|
error("%s", e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loop = new MainLoop();
|
||||||
|
loop.run();
|
||||||
|
|
||||||
|
Gst.deinit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -42,3 +42,11 @@ install_data(
|
||||||
install_data('miracle-gst', 'gstplayer', 'uibc-viewer',
|
install_data('miracle-gst', 'gstplayer', 'uibc-viewer',
|
||||||
install_dir: get_option('bindir'),
|
install_dir: get_option('bindir'),
|
||||||
install_mode: 'rwxr-xr-x')
|
install_mode: 'rwxr-xr-x')
|
||||||
|
|
||||||
|
add_languages('vala')
|
||||||
|
gio2 = dependency('gio-2.0')
|
||||||
|
gst1 = dependency('gstreamer-1.0')
|
||||||
|
gst1_base = dependency('gstreamer-base-1.0')
|
||||||
|
executable('gstencoder', 'gstencoder.vala',
|
||||||
|
dependencies: [gst1, gst1_base, gio2],
|
||||||
|
install: true)
|
||||||
|
|
|
@ -143,8 +143,6 @@ struct ctl_wfd
|
||||||
struct shl_htable sessions;
|
struct shl_htable sessions;
|
||||||
size_t n_sessions;
|
size_t n_sessions;
|
||||||
unsigned int id_pool;
|
unsigned int id_pool;
|
||||||
|
|
||||||
sd_event_source *signal_sources[4];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ctl_wfd * ctl_wfd_get();
|
struct ctl_wfd * ctl_wfd_get();
|
||||||
|
@ -160,6 +158,7 @@ int ctl_wfd_remove_session_by_id(struct ctl_wfd *wfd,
|
||||||
struct wfd_session **out);
|
struct wfd_session **out);
|
||||||
void ctl_wfd_shutdown(struct ctl_wfd *wfd);
|
void ctl_wfd_shutdown(struct ctl_wfd *wfd);
|
||||||
unsigned int ctl_wfd_alloc_session_id(struct ctl_wfd *wfd);
|
unsigned int ctl_wfd_alloc_session_id(struct ctl_wfd *wfd);
|
||||||
|
void ctl_wfd_shutdown(struct ctl_wfd *wfd);
|
||||||
static inline struct sd_event * ctl_wfd_get_loop()
|
static inline struct sd_event * ctl_wfd_get_loop()
|
||||||
{
|
{
|
||||||
return ctl_wfd_get()->loop;
|
return ctl_wfd_get()->loop;
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <gst/gst.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <systemd/sd-event.h>
|
#include <systemd/sd-event.h>
|
||||||
#include <systemd/sd-daemon.h>
|
#include <systemd/sd-daemon.h>
|
||||||
#include "ctl.h"
|
#include "ctl.h"
|
||||||
|
@ -77,8 +78,6 @@ error:
|
||||||
|
|
||||||
static void ctl_wfd_free(struct ctl_wfd *wfd)
|
static void ctl_wfd_free(struct ctl_wfd *wfd)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
if(!wfd) {
|
if(!wfd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -88,13 +87,6 @@ static void ctl_wfd_free(struct ctl_wfd *wfd)
|
||||||
shl_htable_clear_str(&wfd->sinks, NULL, NULL);
|
shl_htable_clear_str(&wfd->sinks, NULL, NULL);
|
||||||
shl_htable_clear_uint(&wfd->sessions, NULL, NULL);
|
shl_htable_clear_uint(&wfd->sessions, NULL, NULL);
|
||||||
|
|
||||||
for(i = 0; i < SHL_ARRAY_LENGTH(wfd->signal_sources); ++ i) {
|
|
||||||
if(wfd->signal_sources[i]) {
|
|
||||||
sd_event_source_set_enabled(wfd->signal_sources[i], SD_EVENT_OFF);
|
|
||||||
sd_event_source_unref(wfd->signal_sources[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(wfd->loop) {
|
if(wfd->loop) {
|
||||||
sd_event_unref(wfd->loop);
|
sd_event_unref(wfd->loop);
|
||||||
}
|
}
|
||||||
|
@ -108,9 +100,6 @@ static int ctl_wfd_handle_shutdown(sd_event_source *s,
|
||||||
{
|
{
|
||||||
struct ctl_wfd *wfd = userdata;
|
struct ctl_wfd *wfd = userdata;
|
||||||
|
|
||||||
sd_event_source_set_enabled(s, false);
|
|
||||||
sd_event_source_unref(s);
|
|
||||||
|
|
||||||
sd_event_exit(wfd->loop, 0);
|
sd_event_exit(wfd->loop, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -283,12 +272,25 @@ static int ctl_wfd_fetch_info(sd_event_source *s, void *userdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctl_wfd_handle_signal(sd_event_source *s,
|
static int ctl_wfd_handle_signal(sd_event_source *s,
|
||||||
const struct signalfd_siginfo *si,
|
const struct signalfd_siginfo *ssi,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
|
siginfo_t siginfo;
|
||||||
struct ctl_wfd *wfd = userdata;
|
struct ctl_wfd *wfd = userdata;
|
||||||
|
|
||||||
sd_event_source_set_enabled(s, false);
|
if(ssi->ssi_signo == SIGCHLD) {
|
||||||
|
r = waitid(P_PID, ssi->ssi_pid, &siginfo, WNOHANG | WEXITED);
|
||||||
|
if(0 > r) {
|
||||||
|
log_warning("failed to reaping child %d", ssi->ssi_pid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log_info("child %d exit: %d",
|
||||||
|
ssi->ssi_pid,
|
||||||
|
siginfo.si_code);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return sd_event_exit(wfd->loop, 0);
|
return sd_event_exit(wfd->loop, 0);
|
||||||
}
|
}
|
||||||
|
@ -296,12 +298,12 @@ static int ctl_wfd_handle_signal(sd_event_source *s,
|
||||||
static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus)
|
static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
const int signals[SHL_ARRAY_LENGTH(wfd->signal_sources)] = {
|
const int signals[] = {
|
||||||
SIGINT, SIGHUP, SIGQUIT, SIGTERM
|
SIGINT, SIGHUP, SIGQUIT, SIGTERM, SIGCHLD,
|
||||||
};
|
};
|
||||||
struct ctl_wifi *wifi;
|
struct ctl_wifi *wifi;
|
||||||
|
|
||||||
for(i = 0; i < SHL_ARRAY_LENGTH(wfd->signal_sources); i ++) {
|
for(i = 0; i < SHL_ARRAY_LENGTH(signals); i ++) {
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
sigemptyset(&mask);
|
sigemptyset(&mask);
|
||||||
sigaddset(&mask, signals[i]);
|
sigaddset(&mask, signals[i]);
|
||||||
|
@ -311,7 +313,7 @@ static int ctl_wfd_init(struct ctl_wfd *wfd, sd_bus *bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_event_add_signal(wfd->loop,
|
r = sd_event_add_signal(wfd->loop,
|
||||||
&wfd->signal_sources[i],
|
NULL,
|
||||||
signals[i],
|
signals[i],
|
||||||
ctl_wfd_handle_signal,
|
ctl_wfd_handle_signal,
|
||||||
wfd);
|
wfd);
|
||||||
|
@ -452,8 +454,6 @@ int main(int argc, char **argv)
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
setlocale(LC_TIME, "en_US.UTF-8");
|
setlocale(LC_TIME, "en_US.UTF-8");
|
||||||
|
|
||||||
gst_init(&argc, &argv);
|
|
||||||
|
|
||||||
if(getenv("LOG_LEVEL")) {
|
if(getenv("LOG_LEVEL")) {
|
||||||
log_max_sev = log_parse_arg(getenv("LOG_LEVEL"));
|
log_max_sev = log_parse_arg(getenv("LOG_LEVEL"));
|
||||||
}
|
}
|
||||||
|
@ -481,20 +481,20 @@ int main(int argc, char **argv)
|
||||||
goto unref_bus;
|
goto unref_bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = ctl_wfd_new(&wfd, event, bus);
|
r = wfd_dbus_new(&wfd_dbus, event, bus);
|
||||||
if(0 > r) {
|
if(0 > r) {
|
||||||
goto bus_detach_event;
|
goto bus_detach_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = wfd_dbus_new(&wfd_dbus, event, bus);
|
r = ctl_wfd_new(&wfd, event, bus);
|
||||||
if(0 > r) {
|
if(0 > r) {
|
||||||
goto free_ctl_wfd;
|
goto free_wfd_dbus;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = wfd_dbus_expose(wfd_dbus);
|
r = wfd_dbus_expose(wfd_dbus);
|
||||||
if(0 > r) {
|
if(0 > r) {
|
||||||
log_warning("unable to publish WFD service: %s", strerror(errno));
|
log_warning("unable to publish WFD service: %s", strerror(errno));
|
||||||
goto free_wfd_dbus;
|
goto free_ctl_wfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_notify(false, "READY=1\n"
|
r = sd_notify(false, "READY=1\n"
|
||||||
|
@ -508,10 +508,10 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
sd_notify(false, "STATUS=Exiting..");
|
sd_notify(false, "STATUS=Exiting..");
|
||||||
|
|
||||||
free_wfd_dbus:
|
|
||||||
wfd_dbus_free(wfd_dbus);
|
|
||||||
free_ctl_wfd:
|
free_ctl_wfd:
|
||||||
ctl_wfd_free(wfd);
|
ctl_wfd_free(wfd);
|
||||||
|
free_wfd_dbus:
|
||||||
|
wfd_dbus_free(wfd_dbus);
|
||||||
bus_detach_event:
|
bus_detach_event:
|
||||||
sd_bus_detach_event(bus);
|
sd_bus_detach_event(bus);
|
||||||
unref_bus:
|
unref_bus:
|
||||||
|
@ -521,7 +521,6 @@ disable_watchdog:
|
||||||
unref_event:
|
unref_event:
|
||||||
sd_event_unref(event);
|
sd_event_unref(event);
|
||||||
end:
|
end:
|
||||||
gst_deinit();
|
|
||||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <gst/gst.h>
|
|
||||||
#include <gst/base/gstbasesrc.h>
|
|
||||||
#include "wfd-session.h"
|
#include "wfd-session.h"
|
||||||
#include "shl_log.h"
|
#include "shl_log.h"
|
||||||
#include "rtsp.h"
|
#include "rtsp.h"
|
||||||
|
@ -48,6 +46,8 @@ struct wfd_out_session
|
||||||
sd_event_source *gst_launch_source;
|
sd_event_source *gst_launch_source;
|
||||||
sd_event_source *gst_term_source;
|
sd_event_source *gst_term_source;
|
||||||
|
|
||||||
|
sd_event_source *encoder_source;
|
||||||
|
|
||||||
enum wfd_display_type display_type;
|
enum wfd_display_type display_type;
|
||||||
char *authority;
|
char *authority;
|
||||||
char *display_name;
|
char *display_name;
|
||||||
|
@ -61,10 +61,12 @@ struct wfd_out_session
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
char *audio_dev;
|
char *audio_dev;
|
||||||
|
|
||||||
GstElement *pipeline;
|
/*GstElement *pipeline;*/
|
||||||
GstBus *bus;
|
/*GstBus *bus;*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int force_proc_exit(pid_t pid);
|
||||||
|
|
||||||
static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[];
|
static const struct rtsp_dispatch_entry out_session_rtsp_disp_tbl[];
|
||||||
|
|
||||||
int wfd_out_session_new(struct wfd_session **out,
|
int wfd_out_session_new(struct wfd_session **out,
|
||||||
|
@ -296,12 +298,22 @@ int wfd_out_session_teardown(struct wfd_session *s)
|
||||||
|
|
||||||
void wfd_out_session_destroy(struct wfd_session *s)
|
void wfd_out_session_destroy(struct wfd_session *s)
|
||||||
{
|
{
|
||||||
|
pid_t pid;
|
||||||
struct wfd_out_session *os = wfd_out_session(s);
|
struct wfd_out_session *os = wfd_out_session(s);
|
||||||
if(0 <= os->fd) {
|
if(0 <= os->fd) {
|
||||||
close(os->fd);
|
close(os->fd);
|
||||||
os->fd = -1;
|
os->fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(os->encoder_source) {
|
||||||
|
sd_event_source_get_child_pid(os->encoder_source, &pid);
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
|
||||||
|
sd_event_source_set_userdata(os->encoder_source, NULL);
|
||||||
|
sd_event_source_unref(os->encoder_source);
|
||||||
|
os->encoder_source = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*if(os->gst_launch_source) {*/
|
/*if(os->gst_launch_source) {*/
|
||||||
/*sd_event_source_unref(os->gst_launch_source);*/
|
/*sd_event_source_unref(os->gst_launch_source);*/
|
||||||
/*os->gst_launch_source = NULL;*/
|
/*os->gst_launch_source = NULL;*/
|
||||||
|
@ -322,17 +334,17 @@ void wfd_out_session_destroy(struct wfd_session *s)
|
||||||
os->authority = NULL;
|
os->authority = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(os->bus) {
|
/*if(os->bus) {*/
|
||||||
gst_bus_remove_watch(os->bus);
|
/*gst_bus_remove_watch(os->bus);*/
|
||||||
g_object_unref(os->bus);
|
/*g_object_unref(os->bus);*/
|
||||||
os->bus = NULL;
|
/*os->bus = NULL;*/
|
||||||
}
|
/*}*/
|
||||||
|
|
||||||
if(os->pipeline) {
|
/*if(os->pipeline) {*/
|
||||||
gst_element_set_state(os->pipeline, GST_STATE_NULL);
|
/*gst_element_set_state(os->pipeline, GST_STATE_NULL);*/
|
||||||
g_object_unref(os->pipeline);
|
/*g_object_unref(os->pipeline);*/
|
||||||
os->pipeline = NULL;
|
/*os->pipeline = NULL;*/
|
||||||
}
|
/*}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
int wfd_out_session_initiate_request(struct wfd_session *s)
|
int wfd_out_session_initiate_request(struct wfd_session *s)
|
||||||
|
@ -546,43 +558,43 @@ static int wfd_out_session_request_options(struct wfd_session *s,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean wfd_out_session_handle_gst_message(GstBus *bus,
|
//static gboolean wfd_out_session_handle_gst_message(GstBus *bus,
|
||||||
GstMessage *m,
|
// GstMessage *m,
|
||||||
gpointer userdata)
|
// gpointer userdata)
|
||||||
{
|
//{
|
||||||
struct wfd_session *s = userdata;
|
// struct wfd_session *s = userdata;
|
||||||
struct wfd_out_session *os = userdata;
|
// struct wfd_out_session *os = userdata;
|
||||||
GstState old_state, new_state;
|
// GstState old_state, new_state;
|
||||||
|
//
|
||||||
switch(GST_MESSAGE_TYPE(m)) {
|
// switch(GST_MESSAGE_TYPE(m)) {
|
||||||
case GST_MESSAGE_STATE_CHANGED:
|
// case GST_MESSAGE_STATE_CHANGED:
|
||||||
if(os->pipeline != (void *) GST_MESSAGE_SRC(m)) {
|
// if(os->pipeline != (void *) GST_MESSAGE_SRC(m)) {
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
gst_message_parse_state_changed(m, &old_state, &new_state, NULL);
|
// gst_message_parse_state_changed(m, &old_state, &new_state, NULL);
|
||||||
if(GST_STATE_PLAYING == new_state) {
|
// if(GST_STATE_PLAYING == new_state) {
|
||||||
log_info("stream is playing");
|
// log_info("stream is playing");
|
||||||
wfd_session_set_state(s, WFD_SESSION_STATE_PLAYING);
|
// wfd_session_set_state(s, WFD_SESSION_STATE_PLAYING);
|
||||||
}
|
// }
|
||||||
else if(GST_STATE_PLAYING == old_state &&
|
// else if(GST_STATE_PLAYING == old_state &&
|
||||||
GST_STATE_PAUSED == new_state) {
|
// GST_STATE_PAUSED == new_state) {
|
||||||
log_info("stream is paused");
|
// log_info("stream is paused");
|
||||||
wfd_session_set_state(s, WFD_SESSION_STATE_PAUSED);
|
// wfd_session_set_state(s, WFD_SESSION_STATE_PAUSED);
|
||||||
}
|
// }
|
||||||
break;
|
// break;
|
||||||
case GST_MESSAGE_EOS:
|
// case GST_MESSAGE_EOS:
|
||||||
case GST_MESSAGE_ERROR:
|
// case GST_MESSAGE_ERROR:
|
||||||
log_warning("%s encounter unexpected error or EOS",
|
// log_warning("%s encounter unexpected error or EOS",
|
||||||
GST_MESSAGE_SRC_NAME(m));
|
// GST_MESSAGE_SRC_NAME(m));
|
||||||
wfd_session_teardown(s);
|
// wfd_session_teardown(s);
|
||||||
break;
|
// break;
|
||||||
default:
|
// default:
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return TRUE;
|
// return TRUE;
|
||||||
}
|
//}
|
||||||
|
|
||||||
inline static char * uint16_to_str(uint16_t i, char *buf, size_t len)
|
inline static char * uint16_to_str(uint16_t i, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -598,189 +610,276 @@ inline static char * quote_str(const char *s, char *d, size_t len)
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wfd_out_session_create_pipeline(struct wfd_session *s)
|
static int force_proc_exit(pid_t pid)
|
||||||
{
|
{
|
||||||
char rrtp_port[16], rrtcp_port[16], lrtcp_port[16];
|
siginfo_t siginfo;
|
||||||
char audio_dev[256];
|
int r = kill(pid, SIGKILL);
|
||||||
char vsrc_param1[16] = "", vsrc_param2[16] = "";
|
|
||||||
char vsrc_param3[16] = "", vsrc_param4[16] = "";
|
|
||||||
struct wfd_out_session *os = wfd_out_session(s);
|
|
||||||
GstElement *pipeline;
|
|
||||||
GstElement *vsrc;
|
|
||||||
GstBus *bus;
|
|
||||||
GError *error = NULL;
|
|
||||||
const char **tmp;
|
|
||||||
int r;
|
|
||||||
const char *pipeline_desc[128] = {
|
|
||||||
"ximagesrc",
|
|
||||||
"name=vsrc",
|
|
||||||
"use-damage=false",
|
|
||||||
"show-pointer=false",
|
|
||||||
vsrc_param1,
|
|
||||||
vsrc_param2,
|
|
||||||
vsrc_param3,
|
|
||||||
vsrc_param4,
|
|
||||||
"!", "video/x-raw,",
|
|
||||||
"framerate=30/1",
|
|
||||||
//"!", "vaapipostproc",
|
|
||||||
// "scale-method=2", /* high quality scaling mode */
|
|
||||||
// "format=3", /* yv12" */
|
|
||||||
//"!", "vaapih264enc",
|
|
||||||
// "rate-control=1",
|
|
||||||
// "num-slices=1", /* in WFD spec, one slice per frame */
|
|
||||||
// "max-bframes=0", /* in H264 CHP, no bframe supporting */
|
|
||||||
// "cabac=true", /* in H264 CHP, CABAC entropy codeing is supported, but need more processing to decode */
|
|
||||||
// "dct8x8=true", /* in H264 CHP, DTC is supported */
|
|
||||||
// "cpb-length=50", /* shortent buffer in order to decrease latency */
|
|
||||||
// "keyframe-period=30",
|
|
||||||
// /* "bitrate=62500", */ /* the max bitrate of H264 level 4.2, crashing my dongle, let codec decide */
|
|
||||||
"!", "videoscale",
|
|
||||||
"method=0",
|
|
||||||
"!", "video/x-raw,",
|
|
||||||
"width=1920,",
|
|
||||||
"height=1080",
|
|
||||||
"!", "videoconvert",
|
|
||||||
"dither=0",
|
|
||||||
"!", "video/x-raw,",
|
|
||||||
"format=YV12"
|
|
||||||
"!", "x264enc",
|
|
||||||
"pass=4", /* constant quantizer */
|
|
||||||
"b-adapt=false", /* no bframe suppport in CHP */
|
|
||||||
"key-int-max=30", /* send IDR pictures per second */
|
|
||||||
"speed-preset=4", /* faster */
|
|
||||||
"tune=4", /* zero latency */
|
|
||||||
"!", "h264parse",
|
|
||||||
"!", "video/x-h264,",
|
|
||||||
"alignment=nal,",
|
|
||||||
"stream-format=byte-stream"
|
|
||||||
"!", "queue",
|
|
||||||
"max-size-buffers=0",
|
|
||||||
"max-size-bytes=0",
|
|
||||||
"!", "mpegtsmux",
|
|
||||||
"name=muxer",
|
|
||||||
"!", "rtpmp2tpay",
|
|
||||||
"!", ".send_rtp_sink_0", "rtpbin",
|
|
||||||
"name=session",
|
|
||||||
"do-retransmission=true",
|
|
||||||
"do-sync-event=true",
|
|
||||||
"do-lost=true",
|
|
||||||
"ntp-time-source=3",
|
|
||||||
"buffer-mode=0",
|
|
||||||
"latency=20",
|
|
||||||
"max-misorder-time=30",
|
|
||||||
"!", "application/x-rtp",
|
|
||||||
"!", "udpsink",
|
|
||||||
"sync=false",
|
|
||||||
"async=false",
|
|
||||||
"host=", wfd_out_session_get_sink(s)->peer->remote_address,
|
|
||||||
"port=", uint16_to_str(s->stream.rtp_port, rrtp_port,sizeof(rrtp_port)),
|
|
||||||
"udpsrc",
|
|
||||||
"address=", wfd_out_session_get_sink(s)->peer->local_address,
|
|
||||||
"port=", uint16_to_str(LOCAL_RTCP_PORT, lrtcp_port,sizeof(lrtcp_port)),
|
|
||||||
"reuse=true",
|
|
||||||
"!", "session.recv_rtcp_sink_0",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
if(s->stream.rtcp_port) {
|
|
||||||
for(tmp = pipeline_desc; *tmp; ++tmp);
|
|
||||||
*tmp ++ = "session.send_rtcp_src_0";
|
|
||||||
*tmp ++ = "!";
|
|
||||||
*tmp ++ = "udpsink";
|
|
||||||
*tmp ++ = "host=";
|
|
||||||
*tmp ++ = wfd_out_session_get_sink(s)->peer->remote_address;
|
|
||||||
*tmp ++ = "port=";
|
|
||||||
*tmp ++ = uint16_to_str(s->stream.rtcp_port, rrtcp_port,sizeof(rrtcp_port));
|
|
||||||
*tmp ++ = "sync=false";
|
|
||||||
*tmp ++ = "async=false";
|
|
||||||
*tmp ++ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(*os->audio_dev) {
|
|
||||||
for(tmp = pipeline_desc; *tmp; ++tmp);
|
|
||||||
*tmp ++ = "pulsesrc";
|
|
||||||
*tmp ++ = "do-timestamp=true";
|
|
||||||
*tmp ++ = "client-name=miraclecast";
|
|
||||||
*tmp ++ = "device=";
|
|
||||||
*tmp ++ = quote_str(os->audio_dev, audio_dev, sizeof(audio_dev));
|
|
||||||
*tmp ++ = "!";
|
|
||||||
*tmp ++ = "voaacenc";
|
|
||||||
*tmp ++ = "mark-granule=true";
|
|
||||||
*tmp ++ = "hard-resync=true";
|
|
||||||
*tmp ++ = "tolerance=40";
|
|
||||||
*tmp ++ = "!";
|
|
||||||
*tmp ++ = "audio/mpeg,";
|
|
||||||
*tmp ++ = "rate=48000,";
|
|
||||||
*tmp ++ = "channels=2,";
|
|
||||||
*tmp ++ = "stream-format=adts,";
|
|
||||||
*tmp ++ = "base-profile=lc";
|
|
||||||
*tmp ++ = "!";
|
|
||||||
*tmp ++ = "queue";
|
|
||||||
*tmp ++ = "max-size-buffers=0";
|
|
||||||
*tmp ++ = "max-size-bytes=0";
|
|
||||||
*tmp ++ = "max-size-time=0";
|
|
||||||
*tmp ++ = "!";
|
|
||||||
*tmp ++ = "muxer.";
|
|
||||||
*tmp ++ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* bad pratice, but since we are in the same process,
|
|
||||||
I think this is the only way to do it */
|
|
||||||
if(WFD_DISPLAY_TYPE_X == os->display_type) {
|
|
||||||
r = setenv("XAUTHORITY", os->authority, 1);
|
|
||||||
if(0 > r) {
|
if(0 > r) {
|
||||||
|
log_warning("failed to kill encoder (pid %d): %s",
|
||||||
|
pid,
|
||||||
|
strerror(errno));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = setenv("DISPLAY", os->display_name, 1);
|
r = waitid(P_PID, pid, &siginfo, 0);
|
||||||
if(0 > r) {
|
if(0 > r) {
|
||||||
|
log_warning("failed to wait for encoder (pid %d) exit: %s",
|
||||||
|
pid,
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!os->display_param_name) {
|
static int wfd_out_session_handle_encoder_exit(sd_event_source *source,
|
||||||
snprintf(vsrc_param1, sizeof(vsrc_param1), "startx=%hu", os->x);
|
const siginfo_t *siginfo,
|
||||||
snprintf(vsrc_param2, sizeof(vsrc_param2), "starty=%hu", os->y);
|
void *userdata)
|
||||||
snprintf(vsrc_param3, sizeof(vsrc_param3), "endx=%d", os->x + os->width - 1);
|
{
|
||||||
snprintf(vsrc_param4, sizeof(vsrc_param4), "endy=%d", os->y + os->height - 1);
|
struct wfd_out_session *os = userdata;
|
||||||
}
|
pid_t pid;
|
||||||
else if(!strcmp("xid", os->display_param_name) ||
|
|
||||||
!strcmp("xname", os->display_param_name)) {
|
|
||||||
snprintf(vsrc_param1, sizeof(vsrc_param1),
|
|
||||||
"%s=\"%s\"",
|
|
||||||
os->display_param_name,
|
|
||||||
os->display_param_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline = gst_parse_launchv(pipeline_desc, &error);
|
sd_event_source_get_child_pid(source, &pid);
|
||||||
if(!pipeline) {
|
log_info("encoder %d exited", pid);
|
||||||
if(error) {
|
|
||||||
log_error("failed to create pipeline: %s", error->message);
|
sd_event_source_set_enabled(source, false);
|
||||||
g_error_free(error);
|
sd_event_source_unref(source);
|
||||||
|
|
||||||
|
if(os) {
|
||||||
|
os->encoder_source = NULL;
|
||||||
|
wfd_session_teardown(wfd_session(os));
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
vsrc = gst_bin_get_by_name(GST_BIN(pipeline), "vsrc");
|
|
||||||
gst_base_src_set_live(GST_BASE_SRC(vsrc), true);
|
|
||||||
g_object_unref(vsrc);
|
|
||||||
vsrc = NULL;
|
|
||||||
|
|
||||||
r = gst_element_set_state(pipeline, GST_STATE_PAUSED);
|
|
||||||
if(GST_STATE_CHANGE_FAILURE == r) {
|
|
||||||
g_object_unref(pipeline);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bus = gst_element_get_bus(pipeline);
|
|
||||||
gst_bus_add_watch(bus, wfd_out_session_handle_gst_message, s);
|
|
||||||
|
|
||||||
os->pipeline = pipeline;
|
|
||||||
os->bus = bus;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int wfd_out_session_create_pipeline(struct wfd_session *s)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
pid_t pid;
|
||||||
|
sigset_t mask;
|
||||||
|
struct wfd_out_session *os = wfd_out_session(s);
|
||||||
|
|
||||||
|
if(os->encoder_source) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if(0 > pid) {
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
else if(0 < pid) {
|
||||||
|
log_info("forked child %d", pid);
|
||||||
|
r = sd_event_add_child(ctl_wfd_get_loop(),
|
||||||
|
&os->encoder_source,
|
||||||
|
pid,
|
||||||
|
WEXITED,
|
||||||
|
wfd_out_session_handle_encoder_exit,
|
||||||
|
s);
|
||||||
|
if(0 > r) {
|
||||||
|
force_proc_exit(pid);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("exec gstencoder");
|
||||||
|
|
||||||
|
setuid(1000);
|
||||||
|
setgid(1000);
|
||||||
|
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||||
|
|
||||||
|
r = execvpe("gstencoder",
|
||||||
|
(char *[]){ "gstencoder", NULL },
|
||||||
|
(char *[]){ "DISPLAY=:0", "XAUTHORITY=/run/user/1000/gdm/Xauthority", "G_MESSAGES_DEBUG=all", "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", NULL });
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//static int wfd_out_session_create_pipeline(struct wfd_session *s)
|
||||||
|
//{
|
||||||
|
// char rrtp_port[16], rrtcp_port[16], lrtcp_port[16];
|
||||||
|
// char audio_dev[256];
|
||||||
|
// char vsrc_param1[16] = "", vsrc_param2[16] = "";
|
||||||
|
// char vsrc_param3[16] = "", vsrc_param4[16] = "";
|
||||||
|
// struct wfd_out_session *os = wfd_out_session(s);
|
||||||
|
// GstElement *pipeline;
|
||||||
|
// GstElement *vsrc;
|
||||||
|
// GstBus *bus;
|
||||||
|
// GError *error = NULL;
|
||||||
|
// const char **tmp;
|
||||||
|
// int r;
|
||||||
|
// const char *pipeline_desc[128] = {
|
||||||
|
// "ximagesrc",
|
||||||
|
// "name=vsrc",
|
||||||
|
// "use-damage=false",
|
||||||
|
// "show-pointer=false",
|
||||||
|
// vsrc_param1,
|
||||||
|
// vsrc_param2,
|
||||||
|
// vsrc_param3,
|
||||||
|
// vsrc_param4,
|
||||||
|
// "!", "video/x-raw,",
|
||||||
|
// "framerate=30/1",
|
||||||
|
// //"!", "vaapipostproc",
|
||||||
|
// // "scale-method=2", /* high quality scaling mode */
|
||||||
|
// // "format=3", /* yv12" */
|
||||||
|
// //"!", "vaapih264enc",
|
||||||
|
// // "rate-control=1",
|
||||||
|
// // "num-slices=1", /* in WFD spec, one slice per frame */
|
||||||
|
// // "max-bframes=0", /* in H264 CHP, no bframe supporting */
|
||||||
|
// // "cabac=true", /* in H264 CHP, CABAC entropy codeing is supported, but need more processing to decode */
|
||||||
|
// // "dct8x8=true", /* in H264 CHP, DTC is supported */
|
||||||
|
// // "cpb-length=50", /* shortent buffer in order to decrease latency */
|
||||||
|
// // "keyframe-period=30",
|
||||||
|
// // /* "bitrate=62500", */ /* the max bitrate of H264 level 4.2, crashing my dongle, let codec decide */
|
||||||
|
// "!", "videoscale",
|
||||||
|
// "method=0",
|
||||||
|
// "!", "video/x-raw,",
|
||||||
|
// "width=1920,",
|
||||||
|
// "height=1080",
|
||||||
|
// "!", "videoconvert",
|
||||||
|
// "dither=0",
|
||||||
|
// "!", "video/x-raw,",
|
||||||
|
// "format=YV12"
|
||||||
|
// "!", "x264enc",
|
||||||
|
// "pass=4", /* constant quantizer */
|
||||||
|
// "b-adapt=false", /* no bframe suppport in CHP */
|
||||||
|
// "key-int-max=30", /* send IDR pictures per second */
|
||||||
|
// "speed-preset=4", /* faster */
|
||||||
|
// "tune=4", /* zero latency */
|
||||||
|
// "!", "h264parse",
|
||||||
|
// "!", "video/x-h264,",
|
||||||
|
// "alignment=nal,",
|
||||||
|
// "stream-format=byte-stream"
|
||||||
|
// "!", "queue",
|
||||||
|
// "max-size-buffers=0",
|
||||||
|
// "max-size-bytes=0",
|
||||||
|
// "!", "mpegtsmux",
|
||||||
|
// "name=muxer",
|
||||||
|
// "!", "rtpmp2tpay",
|
||||||
|
// "!", ".send_rtp_sink_0", "rtpbin",
|
||||||
|
// "name=session",
|
||||||
|
// "do-retransmission=true",
|
||||||
|
// "do-sync-event=true",
|
||||||
|
// "do-lost=true",
|
||||||
|
// "ntp-time-source=3",
|
||||||
|
// "buffer-mode=0",
|
||||||
|
// "latency=20",
|
||||||
|
// "max-misorder-time=30",
|
||||||
|
// "!", "application/x-rtp",
|
||||||
|
// "!", "udpsink",
|
||||||
|
// "sync=false",
|
||||||
|
// "async=false",
|
||||||
|
// "host=", wfd_out_session_get_sink(s)->peer->remote_address,
|
||||||
|
// "port=", uint16_to_str(s->stream.rtp_port, rrtp_port,sizeof(rrtp_port)),
|
||||||
|
// "udpsrc",
|
||||||
|
// "address=", wfd_out_session_get_sink(s)->peer->local_address,
|
||||||
|
// "port=", uint16_to_str(LOCAL_RTCP_PORT, lrtcp_port,sizeof(lrtcp_port)),
|
||||||
|
// "reuse=true",
|
||||||
|
// "!", "session.recv_rtcp_sink_0",
|
||||||
|
// NULL
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// if(s->stream.rtcp_port) {
|
||||||
|
// for(tmp = pipeline_desc; *tmp; ++tmp);
|
||||||
|
// *tmp ++ = "session.send_rtcp_src_0";
|
||||||
|
// *tmp ++ = "!";
|
||||||
|
// *tmp ++ = "udpsink";
|
||||||
|
// *tmp ++ = "host=";
|
||||||
|
// *tmp ++ = wfd_out_session_get_sink(s)->peer->remote_address;
|
||||||
|
// *tmp ++ = "port=";
|
||||||
|
// *tmp ++ = uint16_to_str(s->stream.rtcp_port, rrtcp_port,sizeof(rrtcp_port));
|
||||||
|
// *tmp ++ = "sync=false";
|
||||||
|
// *tmp ++ = "async=false";
|
||||||
|
// *tmp ++ = NULL;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(*os->audio_dev) {
|
||||||
|
// for(tmp = pipeline_desc; *tmp; ++tmp);
|
||||||
|
// *tmp ++ = "pulsesrc";
|
||||||
|
// *tmp ++ = "do-timestamp=true";
|
||||||
|
// *tmp ++ = "client-name=miraclecast";
|
||||||
|
// *tmp ++ = "device=";
|
||||||
|
// *tmp ++ = quote_str(os->audio_dev, audio_dev, sizeof(audio_dev));
|
||||||
|
// *tmp ++ = "!";
|
||||||
|
// *tmp ++ = "voaacenc";
|
||||||
|
// *tmp ++ = "mark-granule=true";
|
||||||
|
// *tmp ++ = "hard-resync=true";
|
||||||
|
// *tmp ++ = "tolerance=40";
|
||||||
|
// *tmp ++ = "!";
|
||||||
|
// *tmp ++ = "audio/mpeg,";
|
||||||
|
// *tmp ++ = "rate=48000,";
|
||||||
|
// *tmp ++ = "channels=2,";
|
||||||
|
// *tmp ++ = "stream-format=adts,";
|
||||||
|
// *tmp ++ = "base-profile=lc";
|
||||||
|
// *tmp ++ = "!";
|
||||||
|
// *tmp ++ = "queue";
|
||||||
|
// *tmp ++ = "max-size-buffers=0";
|
||||||
|
// *tmp ++ = "max-size-bytes=0";
|
||||||
|
// *tmp ++ = "max-size-time=0";
|
||||||
|
// *tmp ++ = "!";
|
||||||
|
// *tmp ++ = "muxer.";
|
||||||
|
// *tmp ++ = NULL;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /* bad pratice, but since we are in the same process,
|
||||||
|
// I think this is the only way to do it */
|
||||||
|
// if(WFD_DISPLAY_TYPE_X == os->display_type) {
|
||||||
|
// r = setenv("XAUTHORITY", os->authority, 1);
|
||||||
|
// if(0 > r) {
|
||||||
|
// return r;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// r = setenv("DISPLAY", os->display_name, 1);
|
||||||
|
// if(0 > r) {
|
||||||
|
// return r;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(!os->display_param_name) {
|
||||||
|
// snprintf(vsrc_param1, sizeof(vsrc_param1), "startx=%hu", os->x);
|
||||||
|
// snprintf(vsrc_param2, sizeof(vsrc_param2), "starty=%hu", os->y);
|
||||||
|
// snprintf(vsrc_param3, sizeof(vsrc_param3), "endx=%d", os->x + os->width - 1);
|
||||||
|
// snprintf(vsrc_param4, sizeof(vsrc_param4), "endy=%d", os->y + os->height - 1);
|
||||||
|
// }
|
||||||
|
// else if(!strcmp("xid", os->display_param_name) ||
|
||||||
|
// !strcmp("xname", os->display_param_name)) {
|
||||||
|
// snprintf(vsrc_param1, sizeof(vsrc_param1),
|
||||||
|
// "%s=\"%s\"",
|
||||||
|
// os->display_param_name,
|
||||||
|
// os->display_param_value);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// pipeline = gst_parse_launchv(pipeline_desc, &error);
|
||||||
|
// if(!pipeline) {
|
||||||
|
// if(error) {
|
||||||
|
// log_error("failed to create pipeline: %s", error->message);
|
||||||
|
// g_error_free(error);
|
||||||
|
// }
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// vsrc = gst_bin_get_by_name(GST_BIN(pipeline), "vsrc");
|
||||||
|
// gst_base_src_set_live(GST_BASE_SRC(vsrc), true);
|
||||||
|
// g_object_unref(vsrc);
|
||||||
|
// vsrc = NULL;
|
||||||
|
//
|
||||||
|
// r = gst_element_set_state(pipeline, GST_STATE_PAUSED);
|
||||||
|
// if(GST_STATE_CHANGE_FAILURE == r) {
|
||||||
|
// g_object_unref(pipeline);
|
||||||
|
// return -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// bus = gst_element_get_bus(pipeline);
|
||||||
|
// gst_bus_add_watch(bus, wfd_out_session_handle_gst_message, s);
|
||||||
|
//
|
||||||
|
// os->pipeline = pipeline;
|
||||||
|
// os->bus = bus;
|
||||||
|
//
|
||||||
|
// return 0;
|
||||||
|
//}
|
||||||
|
|
||||||
static int wfd_out_session_handle_pause_request(struct wfd_session *s,
|
static int wfd_out_session_handle_pause_request(struct wfd_session *s,
|
||||||
struct rtsp_message *req,
|
struct rtsp_message *req,
|
||||||
struct rtsp_message **out_rep)
|
struct rtsp_message **out_rep)
|
||||||
|
@ -788,10 +887,10 @@ static int wfd_out_session_handle_pause_request(struct wfd_session *s,
|
||||||
_rtsp_message_unref_ struct rtsp_message *m = NULL;
|
_rtsp_message_unref_ struct rtsp_message *m = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_READY);
|
// r = gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_READY);
|
||||||
if(GST_STATE_CHANGE_FAILURE == r) {
|
// if(GST_STATE_CHANGE_FAILURE == r) {
|
||||||
return -1;
|
// return -1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
r = rtsp_message_new_reply_for(req,
|
r = rtsp_message_new_reply_for(req,
|
||||||
&m,
|
&m,
|
||||||
|
@ -811,22 +910,36 @@ static int wfd_out_session_handle_teardown_request(struct wfd_session *s,
|
||||||
struct rtsp_message *req,
|
struct rtsp_message *req,
|
||||||
struct rtsp_message **out_rep)
|
struct rtsp_message **out_rep)
|
||||||
{
|
{
|
||||||
_rtsp_message_unref_ struct rtsp_message *m = NULL;
|
pid_t pid;
|
||||||
|
struct wfd_out_session *os = wfd_out_session(s);
|
||||||
|
/*_rtsp_message_unref_ struct rtsp_message *m = NULL;*/
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
wfd_session_set_state(s, WFD_SESSION_STATE_TEARING_DOWN);
|
wfd_session_set_state(s, WFD_SESSION_STATE_TEARING_DOWN);
|
||||||
gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_NULL);
|
/*gst_element_set_state(wfd_out_session(s)->pipeline, GST_STATE_NULL);*/
|
||||||
|
|
||||||
r = rtsp_message_new_reply_for(req,
|
if(!os->encoder_source) {
|
||||||
&m,
|
return 0;
|
||||||
RTSP_CODE_OK,
|
}
|
||||||
NULL);
|
|
||||||
|
r = sd_event_source_get_child_pid(os->encoder_source, &pid);
|
||||||
if(0 > r) {
|
if(0 > r) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_rep = m;
|
log_info("terminating encoder %d", pid);
|
||||||
m = NULL;
|
r = kill(pid, SIGTERM);
|
||||||
|
|
||||||
|
/*r = rtsp_message_new_reply_for(req,*/
|
||||||
|
/*&m,*/
|
||||||
|
/*RTSP_CODE_OK,*/
|
||||||
|
/*NULL);*/
|
||||||
|
/*if(0 > r) {*/
|
||||||
|
/*return r;*/
|
||||||
|
/*}*/
|
||||||
|
|
||||||
|
/**out_rep = m;*/
|
||||||
|
/*m = NULL;*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -836,17 +949,17 @@ static int wfd_out_session_post_handle_play(sd_event_source *source,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
{
|
{
|
||||||
struct wfd_session *s = userdata;
|
struct wfd_session *s = userdata;
|
||||||
GstStateChangeReturn r;
|
//GstStateChangeReturn r;
|
||||||
|
|
||||||
sd_event_source_unref(source);
|
sd_event_source_unref(source);
|
||||||
wfd_out_session(s)->gst_launch_source = NULL;
|
wfd_out_session(s)->gst_launch_source = NULL;
|
||||||
|
|
||||||
r = gst_element_set_state(wfd_out_session(s)->pipeline,
|
/*r = gst_element_set_state(wfd_out_session(s)->pipeline,*/
|
||||||
GST_STATE_PLAYING);
|
/*GST_STATE_PLAYING);*/
|
||||||
if(GST_STATE_CHANGE_FAILURE == r) {
|
/*if(GST_STATE_CHANGE_FAILURE == r) {*/
|
||||||
wfd_session_teardown(s);
|
/*wfd_session_teardown(s);*/
|
||||||
return -1;
|
/*return -1;*/
|
||||||
}
|
/*}*/
|
||||||
|
|
||||||
wfd_session_set_state(s, WFD_SESSION_STATE_PLAYING);
|
wfd_session_set_state(s, WFD_SESSION_STATE_PLAYING);
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ static const char * rtsp_message_id_to_string(enum rtsp_message_id id);
|
||||||
static int wfd_session_handle_request(struct rtsp *bus,
|
static int wfd_session_handle_request(struct rtsp *bus,
|
||||||
struct rtsp_message *m,
|
struct rtsp_message *m,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
static bool wfd_session_is_hup(struct wfd_session *s);
|
|
||||||
static void wfd_session_hup(struct wfd_session *s);
|
static void wfd_session_hup(struct wfd_session *s);
|
||||||
|
|
||||||
const struct wfd_session_vtable session_vtbl[] = {
|
const struct wfd_session_vtable session_vtbl[] = {
|
||||||
|
@ -657,11 +656,6 @@ end:
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wfd_session_is_hup(struct wfd_session *s)
|
|
||||||
{
|
|
||||||
return NULL == s->rtsp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wfd_session_hup(struct wfd_session *s)
|
static void wfd_session_hup(struct wfd_session *s)
|
||||||
{
|
{
|
||||||
if(!s || !s->rtsp) {
|
if(!s || !s->rtsp) {
|
||||||
|
|
Loading…
Reference in a new issue