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