73f39cbaac99b89b1c3d4286c3a5c98bdb52c06a
[platform/upstream/gstreamer.git] / tests / examples / gl / generic / doublecube / main.cpp
1 /*
2  * GStreamer
3  * Copyright (C) 2008-2009 Julien Isorce <julien.isorce@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include <gst/gst.h>
22 #include <gst/gl/gl.h>
23 #include <gst/gl/gstglfuncs.h>
24
25 #include <iostream>
26 #include <sstream>
27 #include <string>
28
29 static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
30 {
31     GMainLoop *loop = (GMainLoop*)data;
32
33     switch (GST_MESSAGE_TYPE (msg))
34     {
35         case GST_MESSAGE_EOS:
36               g_print ("End-of-stream\n");
37               g_main_loop_quit (loop);
38               break;
39         case GST_MESSAGE_ERROR:
40           {
41               gchar *debug = NULL;
42               GError *err = NULL;
43
44               gst_message_parse_error (msg, &err, &debug);
45
46               g_print ("Error: %s\n", err->message);
47               g_error_free (err);
48
49               if (debug)
50               {
51                   g_print ("Debug details: %s\n", debug);
52                   g_free (debug);
53               }
54
55               g_main_loop_quit (loop);
56               break;
57           }
58         default:
59           break;
60     }
61
62     return TRUE;
63 }
64
65
66 //display video framerate
67 static GstPadProbeReturn textoverlay_sink_pad_probe_cb (GstPad *pad, GstPadProbeInfo *info, GstElement* textoverlay)
68 {
69   static GstClockTime last_timestamp = 0;
70   static gint nbFrames = 0 ;
71
72   //display estimated video FPS
73   nbFrames++ ;
74   if (GST_BUFFER_TIMESTAMP(info->data) - last_timestamp >= 1000000000)
75   {
76     gchar *s = g_strdup_printf ("video framerate = %d", nbFrames);
77     g_object_set(G_OBJECT(textoverlay), "text", s, NULL);
78     g_free (s);
79     last_timestamp = GST_BUFFER_TIMESTAMP(info->data) ;
80     nbFrames = 0;
81   }
82
83   return GST_PAD_PROBE_OK;
84 }
85
86
87 //client reshape callback
88 static gboolean reshapeCallback (void *gl_sink, void *context, GLuint width, GLuint height)
89 {
90     glViewport(0, 0, width, height);
91     glMatrixMode(GL_PROJECTION);
92     glLoadIdentity();
93     glMatrixMode(GL_MODELVIEW);
94
95     return TRUE;
96 }
97
98
99 //client draw callback
100 static gboolean drawCallback (GstElement * gl_sink, GstGLContext *context, GstSample * sample, gpointer data)
101 {
102     static GLfloat      xrot = 0;
103     static GLfloat      yrot = 0;
104     static GLfloat      zrot = 0;
105     static GTimeVal current_time;
106     static glong last_sec = current_time.tv_sec;
107     static gint nbFrames = 0;
108
109     GstVideoFrame v_frame;
110     GstVideoInfo v_info;
111     guint texture = 0;
112     GstBuffer *buf = gst_sample_get_buffer (sample);
113     GstCaps *caps = gst_sample_get_caps (sample);
114
115     gst_video_info_from_caps (&v_info, caps);
116
117     if (!gst_video_frame_map (&v_frame, &v_info, buf, (GstMapFlags) (GST_MAP_READ | GST_MAP_GL))) {
118       g_warning ("Failed to map the video buffer");
119       return TRUE;
120     }
121
122     texture = *(guint *) v_frame.data[0];
123
124     g_get_current_time (&current_time);
125     nbFrames++ ;
126
127     if ((current_time.tv_sec - last_sec) >= 1)
128     {
129         std::cout << "GRAPHIC FPS of the scene which contains the custom cube) = " << nbFrames << std::endl;
130         nbFrames = 0;
131         last_sec = current_time.tv_sec;
132     }
133
134     glEnable(GL_DEPTH_TEST);
135
136     glEnable (GL_TEXTURE_2D);
137     glBindTexture (GL_TEXTURE_2D, texture);
138     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
139     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
140     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
141     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
142     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
143
144     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
145     glMatrixMode(GL_MODELVIEW);
146     glLoadIdentity();
147
148     glTranslatef(0.0f,0.0f,-5.0f);
149
150     glRotatef(xrot,1.0f,0.0f,0.0f);
151     glRotatef(yrot,0.0f,1.0f,0.0f);
152     glRotatef(zrot,0.0f,0.0f,1.0f);
153
154     glBegin(GL_QUADS);
155               // Front Face
156               glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
157               glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
158               glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
159               glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
160               // Back Face
161               glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
162               glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
163               glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
164               glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
165               // Top Face
166               glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
167               glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
168               glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
169               glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
170               // Bottom Face
171               glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
172               glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
173               glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
174               glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
175               // Right face
176               glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
177               glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);
178               glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
179               glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
180               // Left Face
181               glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
182               glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
183               glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
184               glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);
185     glEnd();
186
187     gst_video_frame_unmap (&v_frame);
188
189     xrot+=0.03f;
190     yrot+=0.02f;
191     zrot+=0.04f;
192
193     return TRUE;
194 }
195
196
197 static void cb_new_pad (GstElement* decodebin, GstPad* pad, GstElement* element)
198 {
199     GstPad* element_pad = gst_element_get_static_pad (element, "sink");
200
201     //only link once
202     if (!element_pad || GST_PAD_IS_LINKED (element_pad))
203     {
204         gst_object_unref (element_pad);
205         return;
206     }
207
208     GstCaps* caps = gst_pad_get_current_caps (pad);
209     GstStructure* str = gst_caps_get_structure (caps, 0);
210
211     GstCaps* caps2 = gst_pad_query_caps (element_pad, NULL);
212     gst_caps_unref (caps2);
213
214     if (!g_strrstr (gst_structure_get_name (str), "video"))
215     {
216         gst_caps_unref (caps);
217         gst_object_unref (element_pad);
218         return;
219     }
220     gst_caps_unref (caps);
221
222     GstPadLinkReturn ret = gst_pad_link (pad, element_pad);
223     if (ret != GST_PAD_LINK_OK)
224         g_warning ("Failed to link with decodebin %d!\n", ret);
225     gst_object_unref (element_pad);
226 }
227
228
229 gint main (gint argc, gchar *argv[])
230 {
231     if (argc != 2)
232     {
233         g_warning ("usage: doublecube.exe videolocation\n");
234         return -1;
235     }
236
237     std::string video_location(argv[1]);
238
239     /* initialization */
240     gst_init (&argc, &argv);
241     GMainLoop* loop = g_main_loop_new (NULL, FALSE);
242
243     /* create elements */
244     GstElement* pipeline = gst_pipeline_new ("pipeline");
245
246     /* watch for messages on the pipeline's bus (note that this will only
247      * work like this when a GLib main loop is running) */
248     GstBus* bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
249     gst_bus_add_watch (bus, bus_call, loop);
250     gst_object_unref (bus);
251
252     /* create elements */
253     GstElement* videosrc = gst_element_factory_make ("filesrc", "filesrc0");
254     GstElement* decodebin = gst_element_factory_make ("decodebin", "decodebin0");
255     GstElement* videoconvert = gst_element_factory_make ("videoscale", "videoconvert0");
256     GstElement* textoverlay = gst_element_factory_make ("textoverlay", "textoverlay0"); //textoverlay required I420
257     GstElement* tee = gst_element_factory_make ("tee", "tee0");
258
259     GstElement* queue0 = gst_element_factory_make ("queue", "queue0");
260     GstElement* glimagesink0  = gst_element_factory_make ("glimagesink", "glimagesink0");
261
262     GstElement* queue1 = gst_element_factory_make ("queue", "queue1");
263     GstElement* glfiltercube  = gst_element_factory_make ("glfiltercube", "glfiltercube");
264     GstElement* glimagesink1  = gst_element_factory_make ("glimagesink", "glimagesink1");
265
266     GstElement* queue2 = gst_element_factory_make ("queue", "queue2");
267     GstElement* glimagesink2  = gst_element_factory_make ("glimagesink", "glimagesink2");
268
269
270     if (!videosrc || !decodebin || !videoconvert || !textoverlay || !tee ||
271         !queue0 || !glimagesink0 ||
272         !queue1 || !glfiltercube || !glimagesink1 ||
273         !queue2 || !glimagesink2)
274     {
275         g_warning ("one element could not be found \n");
276         return -1;
277     }
278
279     GstCaps* cubecaps = gst_caps_new_simple("video/x-raw",
280                                             "width", G_TYPE_INT, 600,
281                                             "height", G_TYPE_INT, 400,
282                                             NULL);
283
284     /* configure elements */
285     g_object_set(G_OBJECT(videosrc), "num-buffers", 1000, NULL);
286     g_object_set(G_OBJECT(videosrc), "location", video_location.c_str(), NULL);
287     g_object_set(G_OBJECT(textoverlay), "font_desc", "Ahafoni CLM Bold 30", NULL);
288     g_signal_connect(G_OBJECT(glimagesink0), "client-reshape", G_CALLBACK (reshapeCallback), NULL);
289     g_signal_connect(G_OBJECT(glimagesink0), "client-draw", G_CALLBACK (drawCallback), NULL);
290
291     /* add elements */
292     gst_bin_add_many (GST_BIN (pipeline), videosrc, decodebin, videoconvert, textoverlay, tee, 
293                                           queue0, glimagesink0,
294                                           queue1, glfiltercube, glimagesink1,
295                                           queue2, glimagesink2, NULL);
296
297     GstPad* textoverlay_sink_pad = gst_element_get_static_pad (textoverlay, "video_sink");
298     gst_pad_add_probe (textoverlay_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
299                        (GstPadProbeCallback) textoverlay_sink_pad_probe_cb, (gpointer)textoverlay, NULL);
300     gst_object_unref (textoverlay_sink_pad);
301
302     if (!gst_element_link_many(videoconvert, textoverlay, tee, NULL))
303     {
304         g_print ("Failed to link videoconvert to tee!\n");
305         return -1;
306     }
307
308     if (!gst_element_link(videosrc, decodebin))
309     {
310         g_print ("Failed to link videosrc to decodebin!\n");
311         return -1;
312     }
313
314     g_signal_connect (decodebin, "pad-added", G_CALLBACK (cb_new_pad), videoconvert);
315
316     if (!gst_element_link_many(tee, queue0, NULL))
317     {
318         g_warning ("Failed to link one or more elements bettween tee and queue0!\n");
319         return -1;
320     }
321
322     gboolean link_ok = gst_element_link_filtered(queue0, glimagesink0, cubecaps) ;
323     gst_caps_unref(cubecaps) ;
324     if(!link_ok)
325     {
326         g_warning("Failed to link queue0 to glimagesink0!\n") ;
327         return -1 ;
328     }
329
330     if (!gst_element_link_many(tee, queue1, glfiltercube, glimagesink1, NULL))
331     {
332         g_warning ("Failed to link one or more elements bettween tee and glimagesink1!\n");
333         return -1;
334     }
335
336     if (!gst_element_link_many(tee, queue2, glimagesink2, NULL))
337     {
338         g_warning ("Failed to link one or more elements bettween tee and glimagesink2!\n");
339         return -1;
340     }
341
342     /* run */
343     GstStateChangeReturn ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
344     if (ret == GST_STATE_CHANGE_FAILURE)
345     {
346         g_print ("Failed to start up pipeline!\n");
347
348         /* check if there is an error message with details on the bus */
349         GstMessage* msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0);
350         if (msg)
351         {
352           GError *err = NULL;
353
354           gst_message_parse_error (msg, &err, NULL);
355           g_print ("ERROR: %s\n", err->message);
356           g_error_free (err);
357           gst_message_unref (msg);
358         }
359         return -1;
360     }
361
362     g_main_loop_run (loop);
363
364     /* clean up */
365     gst_element_set_state (pipeline, GST_STATE_NULL);
366     gst_object_unref (pipeline);
367
368     return 0;
369 }