gtkvideorenderer.cc revision f9a75d99b92402c56744121b7bc991a9c71cf324
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 39namespace cricket { 40 41class ScopedGdkLock { 42 public: 43 ScopedGdkLock() { 44 gdk_threads_enter(); 45 } 46 47 ~ScopedGdkLock() { 48 gdk_threads_leave(); 49 } 50}; 51 52GtkVideoRenderer::GtkVideoRenderer(int x, int y) 53 : window_(NULL), 54 draw_area_(NULL), 55 initial_x_(x), 56 initial_y_(y) { 57 g_type_init(); 58 // g_thread_init API is deprecated since glib 2.31.0, see release note: 59 // http://mail.gnome.org/archives/gnome-announce-list/2011-October/msg00041.html 60#if !GLIB_CHECK_VERSION(2, 31, 0) 61 g_thread_init(NULL); 62#endif 63 gdk_threads_init(); 64} 65 66GtkVideoRenderer::~GtkVideoRenderer() { 67 if (window_) { 68 ScopedGdkLock lock; 69 gtk_widget_destroy(window_); 70 // Run the Gtk main loop to tear down the window. 71 Pump(); 72 } 73 // Don't need to destroy draw_area_ because it is not top-level, so it is 74 // implicitly destroyed by the above. 75} 76 77bool GtkVideoRenderer::SetSize(int width, int height, int reserved) { 78 ScopedGdkLock lock; 79 80 // For the first frame, initialize the GTK window 81 if ((!window_ && !Initialize(width, height)) || IsClosed()) { 82 return false; 83 } 84 85 image_.reset(new uint8[width * height * 4]); 86 gtk_widget_set_size_request(draw_area_, width, height); 87 return true; 88} 89 90bool GtkVideoRenderer::RenderFrame(const VideoFrame* frame) { 91 if (!frame) { 92 return false; 93 } 94 95 // convert I420 frame to ABGR format, which is accepted by GTK 96 frame->ConvertToRgbBuffer(cricket::FOURCC_ABGR, 97 image_.get(), 98 frame->GetWidth() * frame->GetHeight() * 4, 99 frame->GetWidth() * 4); 100 101 ScopedGdkLock lock; 102 103 if (IsClosed()) { 104 return false; 105 } 106 107 // draw the ABGR image 108 gdk_draw_rgb_32_image(draw_area_->window, 109 draw_area_->style->fg_gc[GTK_STATE_NORMAL], 110 0, 111 0, 112 frame->GetWidth(), 113 frame->GetHeight(), 114 GDK_RGB_DITHER_MAX, 115 image_.get(), 116 frame->GetWidth() * 4); 117 118 // Run the Gtk main loop to refresh the window. 119 Pump(); 120 return true; 121} 122 123bool GtkVideoRenderer::Initialize(int width, int height) { 124 gtk_init(NULL, NULL); 125 window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); 126 draw_area_ = gtk_drawing_area_new(); 127 if (!window_ || !draw_area_) { 128 return false; 129 } 130 131 gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER); 132 gtk_window_set_title(GTK_WINDOW(window_), "Video Renderer"); 133 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); 134 gtk_widget_set_size_request(draw_area_, width, height); 135 gtk_container_add(GTK_CONTAINER(window_), draw_area_); 136 gtk_widget_show_all(window_); 137 gtk_window_move(GTK_WINDOW(window_), initial_x_, initial_y_); 138 139 image_.reset(new uint8[width * height * 4]); 140 return true; 141} 142 143void GtkVideoRenderer::Pump() { 144 while (gtk_events_pending()) { 145 gtk_main_iteration(); 146 } 147} 148 149bool GtkVideoRenderer::IsClosed() const { 150 if (!window_) { 151 // Not initialized yet, so hasn't been closed. 152 return false; 153 } 154 155 if (!GTK_IS_WINDOW(window_) || !GTK_IS_DRAWING_AREA(draw_area_)) { 156 return true; 157 } 158 159 return false; 160} 161 162} // namespace cricket 163