Add a gtk3 port of peerconnection_client on Linux

BUG=668446

Review-Url: https://codereview.webrtc.org/2563203002
Cr-Commit-Position: refs/heads/master@{#15569}
This commit is contained in:
thomasanderson 2016-12-13 02:57:43 -08:00 committed by Commit bot
parent 349092befe
commit ef16e9960f
3 changed files with 91 additions and 64 deletions

View File

@ -15,9 +15,6 @@ if (is_android) {
} else if (is_ios) {
import("//build/config/ios/rules.gni")
}
if (is_linux) {
import("//build/config/linux/pkg_config.gni")
}
group("examples") {
# This target shall build all targets in examples.
@ -432,18 +429,6 @@ if (is_ios || (is_mac && target_cpu != "x86")) {
}
if (is_linux || is_win) {
if (is_linux) {
pkg_config("gtk2_config") {
# Gtk requires gmodule, but it does not list it as a dependency in some
# misconfigured systems.
packages = [
"gmodule-2.0",
"gtk+-2.0",
"gthread-2.0",
]
}
}
config("peerconnection_client_warnings_config") {
cflags = []
if (is_win && is_clang) {
@ -497,6 +482,12 @@ if (is_linux || is_win) {
cflags = [ "/wd4245" ]
configs += [ "//build/config/win:windowed" ]
}
deps = [
"//third_party/libyuv",
"//webrtc/api:libjingle_peerconnection",
"//webrtc/system_wrappers:field_trial_default",
"//webrtc/system_wrappers:metrics_default",
]
if (is_linux) {
sources += [
"peerconnection/client/linux/main.cc",
@ -509,14 +500,8 @@ if (is_linux || is_win) {
"Xext",
"Xrender",
]
public_configs = [ ":gtk2_config" ]
deps += [ "//build/config/linux/gtk" ]
}
deps = [
"//third_party/libyuv",
"//webrtc/api:libjingle_peerconnection",
"//webrtc/system_wrappers:field_trial_default",
"//webrtc/system_wrappers:metrics_default",
]
configs += [ ":peerconnection_client_warnings_config" ]
if (rtc_build_json) {
deps += [ "//third_party/jsoncpp" ]

View File

@ -118,6 +118,12 @@ gboolean Redraw(gpointer data) {
return false;
}
gboolean Draw(GtkWidget* widget, cairo_t* cr, gpointer data) {
GtkMainWnd* wnd = reinterpret_cast<GtkMainWnd*>(data);
wnd->Draw(widget, cr);
return false;
}
} // namespace
//
@ -232,12 +238,20 @@ void GtkMainWnd::SwitchToConnectUI() {
peer_list_ = NULL;
}
#if GTK_MAJOR_VERSION == 2
vbox_ = gtk_vbox_new(FALSE, 5);
#else
vbox_ = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
#endif
GtkWidget* valign = gtk_alignment_new(0, 1, 0, 0);
gtk_container_add(GTK_CONTAINER(vbox_), valign);
gtk_container_add(GTK_CONTAINER(window_), vbox_);
#if GTK_MAJOR_VERSION == 2
GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
#else
GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
#endif
GtkWidget* label = gtk_label_new("Server");
gtk_container_add(GTK_CONTAINER(hbox), label);
@ -317,6 +331,7 @@ void GtkMainWnd::SwitchToStreamingUI() {
draw_area_ = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(window_), draw_area_);
g_signal_connect(G_OBJECT(draw_area_), "draw", G_CALLBACK(&::Draw), this);
gtk_widget_show_all(window_);
}
@ -345,26 +360,35 @@ void GtkMainWnd::OnClicked(GtkWidget* widget) {
void GtkMainWnd::OnKeyPress(GtkWidget* widget, GdkEventKey* key) {
if (key->type == GDK_KEY_PRESS) {
switch (key->keyval) {
case GDK_Escape:
if (draw_area_) {
callback_->DisconnectFromCurrentPeer();
} else if (peer_list_) {
callback_->DisconnectFromServer();
}
break;
#if GTK_MAJOR_VERSION == 2
case GDK_Escape:
#else
case GDK_KEY_Escape:
#endif
if (draw_area_) {
callback_->DisconnectFromCurrentPeer();
} else if (peer_list_) {
callback_->DisconnectFromServer();
}
break;
case GDK_KP_Enter:
case GDK_Return:
if (vbox_) {
OnClicked(NULL);
} else if (peer_list_) {
// OnRowActivated will be called automatically when the user
// presses enter.
}
break;
#if GTK_MAJOR_VERSION == 2
case GDK_KP_Enter:
case GDK_Return:
#else
case GDK_KEY_KP_Enter:
case GDK_KEY_Return:
#endif
if (vbox_) {
OnClicked(NULL);
} else if (peer_list_) {
// OnRowActivated will be called automatically when the user
// presses enter.
}
break;
default:
break;
default:
break;
}
}
}
@ -392,30 +416,30 @@ void GtkMainWnd::OnRedraw() {
VideoRenderer* remote_renderer = remote_renderer_.get();
if (remote_renderer && remote_renderer->image() != NULL &&
draw_area_ != NULL) {
int width = remote_renderer->width();
int height = remote_renderer->height();
width_ = remote_renderer->width();
height_ = remote_renderer->height();
if (!draw_buffer_.get()) {
draw_buffer_size_ = (width * height * 4) * 4;
draw_buffer_size_ = (width_ * height_ * 4) * 4;
draw_buffer_.reset(new uint8_t[draw_buffer_size_]);
gtk_widget_set_size_request(draw_area_, width * 2, height * 2);
gtk_widget_set_size_request(draw_area_, width_ * 2, height_ * 2);
}
const uint32_t* image =
reinterpret_cast<const uint32_t*>(remote_renderer->image());
uint32_t* scaled = reinterpret_cast<uint32_t*>(draw_buffer_.get());
for (int r = 0; r < height; ++r) {
for (int c = 0; c < width; ++c) {
for (int r = 0; r < height_; ++r) {
for (int c = 0; c < width_; ++c) {
int x = c * 2;
scaled[x] = scaled[x + 1] = image[c];
}
uint32_t* prev_line = scaled;
scaled += width * 2;
memcpy(scaled, prev_line, (width * 2) * 4);
scaled += width_ * 2;
memcpy(scaled, prev_line, (width_ * 2) * 4);
image += width;
scaled += width * 2;
image += width_;
scaled += width_ * 2;
}
VideoRenderer* local_renderer = local_renderer_.get();
@ -423,37 +447,50 @@ void GtkMainWnd::OnRedraw() {
image = reinterpret_cast<const uint32_t*>(local_renderer->image());
scaled = reinterpret_cast<uint32_t*>(draw_buffer_.get());
// Position the local preview on the right side.
scaled += (width * 2) - (local_renderer->width() / 2);
scaled += (width_ * 2) - (local_renderer->width() / 2);
// right margin...
scaled -= 10;
// ... towards the bottom.
scaled += (height * width * 4) -
((local_renderer->height() / 2) *
(local_renderer->width() / 2) * 4);
scaled += (height_ * width_ * 4) - ((local_renderer->height() / 2) *
(local_renderer->width() / 2) * 4);
// bottom margin...
scaled -= (width * 2) * 5;
scaled -= (width_ * 2) * 5;
for (int r = 0; r < local_renderer->height(); r += 2) {
for (int c = 0; c < local_renderer->width(); c += 2) {
scaled[c / 2] = image[c + r * local_renderer->width()];
}
scaled += width * 2;
scaled += width_ * 2;
}
}
#if GTK_MAJOR_VERSION == 2
gdk_draw_rgb_32_image(draw_area_->window,
draw_area_->style->fg_gc[GTK_STATE_NORMAL],
0,
0,
width * 2,
height * 2,
GDK_RGB_DITHER_MAX,
draw_buffer_.get(),
(width * 2) * 4);
draw_area_->style->fg_gc[GTK_STATE_NORMAL], 0, 0,
width_ * 2, height_ * 2, GDK_RGB_DITHER_MAX,
draw_buffer_.get(), (width_ * 2) * 4);
#else
gtk_widget_queue_draw(draw_area_);
#endif
}
gdk_threads_leave();
}
void GtkMainWnd::Draw(GtkWidget* widget, cairo_t* cr) {
#if GTK_MAJOR_VERSION != 2
cairo_format_t format = CAIRO_FORMAT_RGB24;
cairo_surface_t* surface = cairo_image_surface_create_for_data(
draw_buffer_.get(), format, width_ * 2, height_ * 2,
cairo_format_stride_for_width(format, width_ * 2));
cairo_set_source_surface(cr, surface, 0, 0);
cairo_rectangle(cr, 0, 0, width_ * 2, height_ * 2);
cairo_fill(cr);
cairo_surface_destroy(surface);
#else
RTC_NOTREACHED();
#endif
}
GtkMainWnd::VideoRenderer::VideoRenderer(
GtkMainWnd* main_wnd,
webrtc::VideoTrackInterface* track_to_render)

View File

@ -24,6 +24,7 @@ typedef struct _GdkEventKey GdkEventKey;
typedef struct _GtkTreeView GtkTreeView;
typedef struct _GtkTreePath GtkTreePath;
typedef struct _GtkTreeViewColumn GtkTreeViewColumn;
typedef struct _cairo cairo_t;
// Implements the main UI of the peer connection client.
// This is functionally equivalent to the MainWnd class in the Windows
@ -71,6 +72,8 @@ class GtkMainWnd : public MainWindow {
void OnRedraw();
void Draw(GtkWidget* widget, cairo_t* cr);
protected:
class VideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
public:
@ -114,6 +117,8 @@ class GtkMainWnd : public MainWindow {
bool autocall_;
std::unique_ptr<VideoRenderer> local_renderer_;
std::unique_ptr<VideoRenderer> remote_renderer_;
int width_;
int height_;
std::unique_ptr<uint8_t[]> draw_buffer_;
int draw_buffer_size_;
};