llmediaimplgstreamervidplug.cpp

Go to the documentation of this file.
00001 
00032 #if LL_GSTREAMER_ENABLED
00033 
00034 #include "linden_common.h"
00035 
00036 #include <gst/gst.h>
00037 #include <gst/video/video.h>
00038 #include <gst/video/gstvideosink.h>
00039 
00040 #include "llmediaimplgstreamer_syms.h"
00041 
00042 #include "llthread.h"
00043 
00044 #include "llmediaimplgstreamervidplug.h"
00045 
00046 GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug);
00047 #define GST_CAT_DEFAULT gst_slvideo_debug
00048 
00049 /* Filter signals and args */
00050 enum
00051 {
00052         /* FILL ME */
00053         LAST_SIGNAL
00054 };
00055 
00056 enum
00057 {
00058         ARG_0
00059 };
00060 
00061 #define SLV_SIZECAPS ", width=(int){1,2,4,8,16,32,64,128,256,512,1024}, height=(int){1,2,4,8,16,32,64,128,256,512,1024} "
00062 #define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS ";" GST_VIDEO_CAPS_BGRx SLV_SIZECAPS
00063 
00064 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE (
00065     "sink",
00066     GST_PAD_SINK,
00067     GST_PAD_ALWAYS,
00068     GST_STATIC_CAPS (SLV_ALLCAPS)
00069     );
00070 
00071 GST_BOILERPLATE (GstSLVideo, gst_slvideo, GstVideoSink,
00072     GST_TYPE_VIDEO_SINK);
00073 
00074 static void gst_slvideo_set_property (GObject * object, guint prop_id,
00075                                       const GValue * value,
00076                                       GParamSpec * pspec);
00077 static void gst_slvideo_get_property (GObject * object, guint prop_id,
00078                                       GValue * value, GParamSpec * pspec);
00079 
00080 static void
00081 gst_slvideo_base_init (gpointer gclass)
00082 {
00083         static GstElementDetails element_details = {
00084                 "PluginTemplate",
00085                 "Generic/PluginTemplate",
00086                 "Generic Template Element",
00087                 "Linden Lab"
00088         };
00089         GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
00090         
00091         llgst_element_class_add_pad_template (element_class,
00092                               llgst_static_pad_template_get (&sink_factory));
00093         llgst_element_class_set_details (element_class, &element_details);
00094 }
00095 
00096 
00097 static void
00098 gst_slvideo_finalize (GObject * object)
00099 {
00100         GstSLVideo *slvideo;
00101         slvideo = GST_SLVIDEO (object);
00102         if (slvideo->caps)
00103         {
00104                 llgst_caps_unref(slvideo->caps);
00105         }
00106 
00107         G_OBJECT_CLASS(parent_class)->finalize (object);
00108 }
00109 
00110 
00111 static GstFlowReturn
00112 gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf)
00113 {
00114         GstSLVideo *slvideo;
00115         llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
00116         
00117         slvideo = GST_SLVIDEO(bsink);
00118         
00119 #if 0
00120         fprintf(stderr, "\n\ntransferring a frame of %dx%d <- %p (%d)\n\n",
00121                 slvideo->width, slvideo->height, GST_BUFFER_DATA(buf),
00122                 slvideo->format);
00123 #endif
00124         if (GST_BUFFER_DATA(buf))
00125         {
00126                 // copy frame and frame info into neutral territory
00127                 GST_OBJECT_LOCK(slvideo);
00128                 slvideo->retained_frame_ready = TRUE;
00129                 slvideo->retained_frame_width = slvideo->width;
00130                 slvideo->retained_frame_height = slvideo->height;
00131                 slvideo->retained_frame_format = slvideo->format;
00132                 int rowbytes = 
00133                         SLVPixelFormatBytes[slvideo->retained_frame_format] *
00134                         slvideo->retained_frame_width;
00135                 int needbytes = rowbytes * slvideo->retained_frame_width;
00136                 // resize retained frame hunk only if necessary
00137                 if (needbytes != slvideo->retained_frame_allocbytes)
00138                 {
00139                         delete[] slvideo->retained_frame_data;
00140                         slvideo->retained_frame_data = new unsigned char[needbytes];
00141                         slvideo->retained_frame_allocbytes = needbytes;
00142                         
00143                 }
00144                 // copy the actual frame data to neutral territory -
00145                 // flipped, for GL reasons
00146                 for (int ypos=0; ypos<slvideo->height; ++ypos)
00147                 {
00148                         memcpy(&slvideo->retained_frame_data[(slvideo->height-1-ypos)*rowbytes],
00149                                &(((unsigned char*)GST_BUFFER_DATA(buf))[ypos*rowbytes]),
00150                                rowbytes);
00151                 }
00152                 // done with the shared data
00153                 GST_OBJECT_UNLOCK(slvideo);
00154         }
00155 
00156         return GST_FLOW_OK;
00157 }
00158 
00159 
00160 static GstStateChangeReturn
00161 gst_slvideo_change_state(GstElement * element, GstStateChange transition)
00162 {
00163         GstSLVideo *slvideo;
00164         GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
00165         
00166         slvideo = GST_SLVIDEO (element);
00167 
00168         switch (transition) {
00169         case GST_STATE_CHANGE_NULL_TO_READY:
00170                 break;
00171         case GST_STATE_CHANGE_READY_TO_PAUSED:
00172                 break;
00173         case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
00174                 break;
00175         default:
00176                 break;
00177         }
00178 
00179         ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
00180         if (ret == GST_STATE_CHANGE_FAILURE)
00181                 return ret;
00182 
00183         switch (transition) {
00184         case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
00185                 break;
00186         case GST_STATE_CHANGE_PAUSED_TO_READY:
00187                 slvideo->fps_n = 0;
00188                 slvideo->fps_d = 1;
00189                 GST_VIDEO_SINK_WIDTH(slvideo) = 0;
00190                 GST_VIDEO_SINK_HEIGHT(slvideo) = 0;
00191                 break;
00192         case GST_STATE_CHANGE_READY_TO_NULL:
00193                 break;
00194         default:
00195                 break;
00196         }
00197 
00198         return ret;
00199 }
00200 
00201 
00202 static GstCaps *
00203 gst_slvideo_get_caps (GstBaseSink * bsink)
00204 {
00205         GstSLVideo *slvideo;
00206         slvideo = GST_SLVIDEO(bsink);
00207         
00208         return llgst_caps_ref (slvideo->caps);
00209 }
00210 
00211 
00212 /* this function handles the link with other elements */
00213 static gboolean
00214 gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps)
00215 {
00216         GstSLVideo *filter;
00217         GstStructure *structure;
00218         GstCaps *intersection;
00219         
00220         GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
00221         
00222         filter = GST_SLVIDEO(bsink);
00223         
00224         intersection = llgst_caps_intersect (filter->caps, caps);
00225         if (llgst_caps_is_empty (intersection))
00226         {
00227                 // no overlap between our caps and requested caps
00228                 return FALSE;
00229         }
00230         llgst_caps_unref(intersection);
00231         
00232         int width, height;
00233         gboolean ret;
00234         const GValue *fps;
00235         const GValue *par;
00236         structure = llgst_caps_get_structure (caps, 0);
00237         ret = llgst_structure_get_int (structure, "width", &width);
00238         ret = ret && llgst_structure_get_int (structure, "height", &height);
00239         fps = llgst_structure_get_value (structure, "framerate");
00240         ret = ret && (fps != NULL);
00241         par = llgst_structure_get_value (structure, "pixel-aspect-ratio");
00242         if (!ret)
00243                 return FALSE;
00244 
00245         filter->width = width;
00246         filter->height = height;
00247         filter->fps_n = llgst_value_get_fraction_numerator(fps);
00248         filter->fps_d = llgst_value_get_fraction_denominator(fps);
00249         if (par)
00250         {
00251                 filter->par_n = llgst_value_get_fraction_numerator(par);
00252                 filter->par_d = llgst_value_get_fraction_denominator(par);
00253         }
00254         else
00255         {
00256                 filter->par_n = 1;
00257                 filter->par_d = 1;
00258         }
00259         GST_VIDEO_SINK_WIDTH(filter) = width;
00260         GST_VIDEO_SINK_HEIGHT(filter) = height;
00261         
00262         filter->format = SLV_PF_UNKNOWN;
00263         if (0 == strcmp(llgst_structure_get_name(structure),
00264                         "video/x-raw-rgb"))
00265         {
00266                 int red_mask;
00267                 int green_mask;
00268                 int blue_mask;
00269                 llgst_structure_get_int(structure, "red_mask", &red_mask);
00270                 llgst_structure_get_int(structure, "green_mask", &green_mask);
00271                 llgst_structure_get_int(structure, "blue_mask", &blue_mask);
00272                 if ((unsigned int)red_mask   == 0xFF000000 &&
00273                     (unsigned int)green_mask == 0x00FF0000 &&
00274                     (unsigned int)blue_mask  == 0x0000FF00)
00275                 {
00276                         filter->format = SLV_PF_RGBX;
00277                         //fprintf(stderr, "\n\nPIXEL FORMAT RGB\n\n");
00278                 } else if ((unsigned int)red_mask   == 0x0000FF00 &&
00279                            (unsigned int)green_mask == 0x00FF0000 &&
00280                            (unsigned int)blue_mask  == 0xFF000000)
00281                 {
00282                         filter->format = SLV_PF_BGRX;
00283                         //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n");
00284                 }
00285         }
00286         
00287         return TRUE;
00288 }
00289 
00290 
00291 static gboolean
00292 gst_slvideo_start (GstBaseSink * bsink)
00293 {
00294         GstSLVideo *slvideo;
00295         gboolean ret = TRUE;
00296         
00297         slvideo = GST_SLVIDEO(bsink);
00298 
00299         return ret;
00300 }
00301 
00302 static gboolean
00303 gst_slvideo_stop (GstBaseSink * bsink)
00304 {
00305         GstSLVideo *slvideo;
00306         slvideo = GST_SLVIDEO(bsink);
00307 
00308         // free-up retained frame buffer
00309         GST_OBJECT_LOCK(slvideo);
00310         slvideo->retained_frame_ready = FALSE;
00311         delete[] slvideo->retained_frame_data;
00312         slvideo->retained_frame_data = NULL;
00313         slvideo->retained_frame_allocbytes = 0;
00314         GST_OBJECT_UNLOCK(slvideo);
00315 
00316         return TRUE;
00317 }
00318 
00319 
00320 static gboolean
00321 gst_slvideo_unlock (GstBaseSink * bsink)
00322 {
00323         // nothing really to do here.
00324         return TRUE;
00325 }
00326 
00327 
00328 /* initialize the plugin's class */
00329 static void
00330 gst_slvideo_class_init (GstSLVideoClass * klass)
00331 {
00332         GObjectClass *gobject_class;
00333         GstElementClass *gstelement_class;
00334         GstBaseSinkClass *gstbasesink_class;
00335         
00336         gobject_class = (GObjectClass *) klass;
00337         gstelement_class = (GstElementClass *) klass;
00338         gstbasesink_class = (GstBaseSinkClass *) klass;
00339         
00340         gobject_class->finalize = gst_slvideo_finalize;
00341         gobject_class->set_property = gst_slvideo_set_property;
00342         gobject_class->get_property = gst_slvideo_get_property;
00343         
00344         gstelement_class->change_state = gst_slvideo_change_state;
00345         
00346         gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_slvideo_get_caps);
00347         gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR( gst_slvideo_set_caps);
00348         //gstbasesink_class->buffer_alloc=GST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc);
00349         //gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_slvideo_get_times);
00350         gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
00351         gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_slvideo_show_frame);
00352         
00353         gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_slvideo_start);
00354         gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_slvideo_stop);
00355         
00356         gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_slvideo_unlock);
00357 }
00358 
00359 
00360 static void
00361 gst_slvideo_update_caps (GstSLVideo * slvideo)
00362 {
00363         GstCaps *caps;
00364 
00365         // GStreamer will automatically convert colourspace if necessary.
00366         // GStreamer will automatically resize media to one of these enumerated
00367         // powers-of-two that we ask for (yay GStreamer!)
00368         caps = llgst_caps_from_string (SLV_ALLCAPS);
00369         
00370         llgst_caps_replace (&slvideo->caps, caps);
00371 }
00372 
00373 
00374 /* initialize the new element
00375  * instantiate pads and add them to element
00376  * set functions
00377  * initialize structure
00378  */
00379 static void
00380 gst_slvideo_init (GstSLVideo * filter,
00381                   GstSLVideoClass * gclass)
00382 {
00383         filter->width = -1;
00384         filter->height = -1;
00385 
00386         // this is the info we share with the client app
00387         GST_OBJECT_LOCK(filter);
00388         filter->retained_frame_ready = FALSE;
00389         filter->retained_frame_data = NULL;
00390         filter->retained_frame_allocbytes = 0;
00391         filter->retained_frame_width = filter->width;
00392         filter->retained_frame_height = filter->height;
00393         filter->retained_frame_format = SLV_PF_UNKNOWN;
00394         GST_OBJECT_UNLOCK(filter);
00395         
00396         gst_slvideo_update_caps(filter);
00397 }
00398 
00399 static void
00400 gst_slvideo_set_property (GObject * object, guint prop_id,
00401                           const GValue * value, GParamSpec * pspec)
00402 {
00403         llg_return_if_fail (GST_IS_SLVIDEO (object));
00404         
00405         switch (prop_id) {
00406         default:
00407                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00408                 break;
00409         }
00410 }
00411 
00412 static void
00413 gst_slvideo_get_property (GObject * object, guint prop_id,
00414                           GValue * value, GParamSpec * pspec)
00415 {
00416         llg_return_if_fail (GST_IS_SLVIDEO (object));
00417 
00418         switch (prop_id) {
00419         default:
00420                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00421                 break;
00422         }
00423 }
00424 
00425 
00426 /* entry point to initialize the plug-in
00427  * initialize the plug-in itself
00428  * register the element factories and pad templates
00429  * register the features
00430  */
00431 static gboolean
00432 plugin_init (GstPlugin * plugin)
00433 {
00434         //fprintf(stderr, "\n\n\nPLUGIN INIT\n\n\n");
00435 
00436         GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, "private-slvideo-plugin",
00437                                  0, "Second Life Video Sink");
00438 
00439         return llgst_element_register (plugin, "private-slvideo",
00440                                        GST_RANK_NONE, GST_TYPE_SLVIDEO);
00441 }
00442 
00443 /* this is the structure that gstreamer looks for to register plugins
00444  */
00445 /* NOTE: Can't rely upon GST_PLUGIN_DEFINE_STATIC to self-register, since
00446    some g++ versions buggily avoid __attribute__((constructor)) functions -
00447    so we provide an explicit plugin init function.
00448  */
00449 void gst_slvideo_init_class (void)
00450 {
00451 #define PACKAGE "packagehack"
00452         static GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
00453                                   GST_VERSION_MINOR,
00454                                   "private-slvideoplugin", 
00455                                   "SL Video sink plugin",
00456                                   plugin_init, "0.1", GST_LICENSE_UNKNOWN,
00457                                   "Second Life",
00458                                   "http://www.secondlife.com/");
00459 #undef PACKAGE
00460         ll_gst_plugin_register_static (&gst_plugin_desc);
00461         //fprintf(stderr, "\n\n\nCLASS INIT\n\n\n");
00462 }
00463 
00464 #endif // LL_GSTREAMER_ENABLED

Generated on Fri May 16 08:32:21 2008 for SecondLife by  doxygen 1.5.5