Merge branch 'move_subdir_bad' into tizen_gst_1.19.2_mono
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst / videosignal / gstvideoanalyse.c
1 /* GStreamer
2  * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17  * Boston, MA 02110-1335, USA.
18  */
19 /**
20  * SECTION:element-videoanalyse
21  * @title: videoanalyse
22  *
23  * This plugin analyses every video frame and if the #GstVideoAnalyse:message
24  * property is %TRUE, posts an element message with video statistics called
25  * `GstVideoAnalyse`.
26  *
27  * The message's structure contains these fields:
28  *
29  * * #GstClockTime `timestamp`: the timestamp of the buffer that triggered the message.
30  *
31  * * #GstClockTime `stream-time`: the stream time of the buffer.
32  *
33  * * #GstClockTime `running-time`: the running_time of the buffer.
34  *
35  * * #GstClockTime`duration`:the duration of the buffer.
36  *
37  * * #gdouble`luma-average`: the average brightness of the frame. Range: 0.0-1.0
38  *
39  * * #gdouble`luma-variance`: the brightness variance of the frame.
40  *
41  * ## Example launch line
42  * |[
43  * gst-launch-1.0 -m videotestsrc ! videoanalyse ! videoconvert ! ximagesink
44  * ]| This pipeline emits messages to the console for each frame that has been analysed.
45  *
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include <gst/gst.h>
53 #include <gst/video/video.h>
54 #include <gst/video/gstvideofilter.h>
55 #include "gstvideoanalyse.h"
56
57 GST_DEBUG_CATEGORY_STATIC (gst_video_analyse_debug_category);
58 #define GST_CAT_DEFAULT gst_video_analyse_debug_category
59
60 /* prototypes */
61
62
63 static void gst_video_analyse_set_property (GObject * object,
64     guint property_id, const GValue * value, GParamSpec * pspec);
65 static void gst_video_analyse_get_property (GObject * object,
66     guint property_id, GValue * value, GParamSpec * pspec);
67 static void gst_video_analyse_finalize (GObject * object);
68
69 static GstFlowReturn gst_video_analyse_transform_frame_ip (GstVideoFilter *
70     filter, GstVideoFrame * frame);
71
72 enum
73 {
74   PROP_0,
75   PROP_MESSAGE
76 };
77
78 #define DEFAULT_MESSAGE TRUE
79
80 #define VIDEO_CAPS \
81     GST_VIDEO_CAPS_MAKE("{ I420, YV12, Y444, Y42B, Y41B }")
82
83
84 /* class initialization */
85
86 G_DEFINE_TYPE_WITH_CODE (GstVideoAnalyse, gst_video_analyse,
87     GST_TYPE_VIDEO_FILTER,
88     GST_DEBUG_CATEGORY_INIT (gst_video_analyse_debug_category, "videoanalyse",
89         0, "debug category for videoanalyse element"));
90 GST_ELEMENT_REGISTER_DEFINE (videoanalyse, "videoanalyse",
91     GST_RANK_NONE, GST_TYPE_VIDEO_ANALYSE);
92
93 static void
94 gst_video_analyse_class_init (GstVideoAnalyseClass * klass)
95 {
96   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
97   GstCaps *tmp = NULL;
98   GstVideoFilterClass *video_filter_class = GST_VIDEO_FILTER_CLASS (klass);
99
100   gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
101       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
102           tmp = gst_caps_from_string (VIDEO_CAPS)));
103   gst_caps_unref (tmp);
104   gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
105       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
106           tmp = gst_caps_from_string (VIDEO_CAPS)));
107   gst_caps_unref (tmp);
108
109   gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
110       "Video analyser", "Filter/Analyzer/Video",
111       "Analyse video signal", "Wim Taymans <wim@fluendo.com>");
112
113   gobject_class->set_property = gst_video_analyse_set_property;
114   gobject_class->get_property = gst_video_analyse_get_property;
115   gobject_class->finalize = gst_video_analyse_finalize;
116   video_filter_class->transform_frame_ip =
117       GST_DEBUG_FUNCPTR (gst_video_analyse_transform_frame_ip);
118
119   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MESSAGE,
120       g_param_spec_boolean ("message", "Message",
121           "Post statics messages",
122           DEFAULT_MESSAGE,
123           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
124   //trans_class->passthrough_on_same_caps = TRUE;
125 }
126
127 static void
128 gst_video_analyse_init (GstVideoAnalyse * videoanalyse)
129 {
130 }
131
132 void
133 gst_video_analyse_set_property (GObject * object, guint property_id,
134     const GValue * value, GParamSpec * pspec)
135 {
136   GstVideoAnalyse *videoanalyse = GST_VIDEO_ANALYSE (object);
137
138   GST_DEBUG_OBJECT (videoanalyse, "set_property");
139
140   switch (property_id) {
141     case PROP_MESSAGE:
142       videoanalyse->message = g_value_get_boolean (value);
143       break;
144     default:
145       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
146       break;
147   }
148 }
149
150 void
151 gst_video_analyse_get_property (GObject * object, guint property_id,
152     GValue * value, GParamSpec * pspec)
153 {
154   GstVideoAnalyse *videoanalyse = GST_VIDEO_ANALYSE (object);
155
156   GST_DEBUG_OBJECT (videoanalyse, "get_property");
157
158   switch (property_id) {
159     case PROP_MESSAGE:
160       g_value_set_boolean (value, videoanalyse->message);
161       break;
162     default:
163       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
164       break;
165   }
166 }
167
168 void
169 gst_video_analyse_finalize (GObject * object)
170 {
171   GstVideoAnalyse *videoanalyse = GST_VIDEO_ANALYSE (object);
172
173   GST_DEBUG_OBJECT (videoanalyse, "finalize");
174
175   /* clean up object here */
176
177   G_OBJECT_CLASS (gst_video_analyse_parent_class)->finalize (object);
178 }
179
180 static void
181 gst_video_analyse_post_message (GstVideoAnalyse * videoanalyse,
182     GstVideoFrame * frame)
183 {
184   GstBaseTransform *trans;
185   GstMessage *m;
186   guint64 duration, timestamp, running_time, stream_time;
187
188   trans = GST_BASE_TRANSFORM_CAST (videoanalyse);
189
190   /* get timestamps */
191   timestamp = GST_BUFFER_TIMESTAMP (frame->buffer);
192   duration = GST_BUFFER_DURATION (frame->buffer);
193   running_time = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
194       timestamp);
195   stream_time = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
196       timestamp);
197
198   m = gst_message_new_element (GST_OBJECT_CAST (videoanalyse),
199       gst_structure_new ("GstVideoAnalyse",
200           "timestamp", G_TYPE_UINT64, timestamp,
201           "stream-time", G_TYPE_UINT64, stream_time,
202           "running-time", G_TYPE_UINT64, running_time,
203           "duration", G_TYPE_UINT64, duration,
204           "luma-average", G_TYPE_DOUBLE, videoanalyse->luma_average,
205           "luma-variance", G_TYPE_DOUBLE, videoanalyse->luma_variance, NULL));
206
207   gst_element_post_message (GST_ELEMENT_CAST (videoanalyse), m);
208 }
209
210 static void
211 gst_video_analyse_planar (GstVideoAnalyse * videoanalyse, GstVideoFrame * frame)
212 {
213   guint64 sum;
214   gint avg, diff;
215   gint i, j;
216   guint8 *d;
217   gint width = frame->info.width;
218   gint height = frame->info.height;
219   gint stride;
220
221   d = frame->data[0];
222   stride = frame->info.stride[0];
223   sum = 0;
224   /* do brightness as average of pixel brightness in 0.0 to 1.0 */
225   for (i = 0; i < height; i++) {
226     for (j = 0; j < width; j++) {
227       sum += d[j];
228     }
229     d += stride;
230   }
231   avg = sum / (width * height);
232   videoanalyse->luma_average = sum / (255.0 * width * height);
233
234   d = frame->data[0];
235   stride = frame->info.stride[0];
236   sum = 0;
237   /* do variance */
238   for (i = 0; i < height; i++) {
239     for (j = 0; j < width; j++) {
240       diff = (avg - d[j]);
241       sum += diff * diff;
242     }
243     d += stride;
244   }
245   videoanalyse->luma_variance = sum / (255.0 * 255.0 * width * height);
246 }
247
248 static GstFlowReturn
249 gst_video_analyse_transform_frame_ip (GstVideoFilter * filter,
250     GstVideoFrame * frame)
251 {
252   GstVideoAnalyse *videoanalyse = GST_VIDEO_ANALYSE (filter);
253
254   GST_DEBUG_OBJECT (videoanalyse, "transform_frame_ip");
255
256   gst_video_analyse_planar (videoanalyse, frame);
257
258   if (videoanalyse->message)
259     gst_video_analyse_post_message (videoanalyse, frame);
260
261   return GST_FLOW_OK;
262 }