• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 // Implementation of GtkVideoRenderer
29 
30 #include "talk/media/devices/gtkvideorenderer.h"
31 
32 #include <gdk/gdk.h>
33 #include <glib.h>
34 #include <gtk/gtk.h>
35 
36 #include "talk/media/base/videocommon.h"
37 #include "talk/media/base/videoframe.h"
38 
39 namespace cricket {
40 
41 class ScopedGdkLock {
42  public:
ScopedGdkLock()43   ScopedGdkLock() {
44     gdk_threads_enter();
45   }
46 
~ScopedGdkLock()47   ~ScopedGdkLock() {
48     gdk_threads_leave();
49   }
50 };
51 
GtkVideoRenderer(int x,int y)52 GtkVideoRenderer::GtkVideoRenderer(int x, int y)
53     : window_(NULL),
54       draw_area_(NULL),
55       initial_x_(x),
56       initial_y_(y),
57       width_(0),
58       height_(0) {
59   g_type_init();
60   // g_thread_init API is deprecated since glib 2.31.0, see release note:
61   // http://mail.gnome.org/archives/gnome-announce-list/2011-October/msg00041.html
62 #if !GLIB_CHECK_VERSION(2, 31, 0)
63   g_thread_init(NULL);
64 #endif
65   gdk_threads_init();
66 }
67 
~GtkVideoRenderer()68 GtkVideoRenderer::~GtkVideoRenderer() {
69   if (window_) {
70     ScopedGdkLock lock;
71     gtk_widget_destroy(window_);
72     // Run the Gtk main loop to tear down the window.
73     Pump();
74   }
75   // Don't need to destroy draw_area_ because it is not top-level, so it is
76   // implicitly destroyed by the above.
77 }
78 
SetSize(int width,int height,int reserved)79 bool GtkVideoRenderer::SetSize(int width, int height, int reserved) {
80   ScopedGdkLock lock;
81 
82   // If the dimension is the same, no-op.
83   if (width_ == width && height_ == height) {
84     return true;
85   }
86 
87   // For the first frame, initialize the GTK window
88   if ((!window_ && !Initialize(width, height)) || IsClosed()) {
89     return false;
90   }
91 
92   image_.reset(new uint8_t[width * height * 4]);
93   gtk_widget_set_size_request(draw_area_, width, height);
94 
95   width_ = width;
96   height_ = height;
97   return true;
98 }
99 
RenderFrame(const VideoFrame * video_frame)100 bool GtkVideoRenderer::RenderFrame(const VideoFrame* video_frame) {
101   if (!video_frame) {
102     return false;
103   }
104 
105   const VideoFrame* frame = video_frame->GetCopyWithRotationApplied();
106 
107   // Need to set size as the frame might be rotated.
108   if (!SetSize(frame->GetWidth(), frame->GetHeight(), 0)) {
109     return false;
110   }
111 
112   // convert I420 frame to ABGR format, which is accepted by GTK
113   frame->ConvertToRgbBuffer(cricket::FOURCC_ABGR,
114                             image_.get(),
115                             frame->GetWidth() * frame->GetHeight() * 4,
116                             frame->GetWidth() * 4);
117 
118   ScopedGdkLock lock;
119 
120   if (IsClosed()) {
121     return false;
122   }
123 
124   // draw the ABGR image
125   gdk_draw_rgb_32_image(draw_area_->window,
126                         draw_area_->style->fg_gc[GTK_STATE_NORMAL],
127                         0,
128                         0,
129                         frame->GetWidth(),
130                         frame->GetHeight(),
131                         GDK_RGB_DITHER_MAX,
132                         image_.get(),
133                         frame->GetWidth() * 4);
134 
135   // Run the Gtk main loop to refresh the window.
136   Pump();
137   return true;
138 }
139 
Initialize(int width,int height)140 bool GtkVideoRenderer::Initialize(int width, int height) {
141   gtk_init(NULL, NULL);
142   window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
143   draw_area_ = gtk_drawing_area_new();
144   if (!window_ || !draw_area_) {
145     return false;
146   }
147 
148   gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER);
149   gtk_window_set_title(GTK_WINDOW(window_), "Video Renderer");
150   gtk_window_set_resizable(GTK_WINDOW(window_), FALSE);
151   gtk_widget_set_size_request(draw_area_, width, height);
152   gtk_container_add(GTK_CONTAINER(window_), draw_area_);
153   gtk_widget_show_all(window_);
154   gtk_window_move(GTK_WINDOW(window_), initial_x_, initial_y_);
155 
156   image_.reset(new uint8_t[width * height * 4]);
157   return true;
158 }
159 
Pump()160 void GtkVideoRenderer::Pump() {
161   while (gtk_events_pending()) {
162     gtk_main_iteration();
163   }
164 }
165 
IsClosed() const166 bool GtkVideoRenderer::IsClosed() const {
167   if (!window_) {
168     // Not initialized yet, so hasn't been closed.
169     return false;
170   }
171 
172   if (!GTK_IS_WINDOW(window_) || !GTK_IS_DRAWING_AREA(draw_area_)) {
173     return true;
174   }
175 
176   return false;
177 }
178 
179 }  // namespace cricket
180