2 * Copyright (C) 2011 Entropy Wave Inc <ds@entropywave.com>
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.
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.
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.
20 * SECTION:element-scenechange
21 * @title: gstscenechange
23 * The scenechange element detects scene changes (also known as shot
24 * changes) in a video stream, and sends a signal when this occurs.
25 * Applications can listen to this signal and make changes to the
26 * pipeline such as cutting the stream. In addition, whenever a
27 * scene change is detected, a custom downstream "GstForceKeyUnit"
28 * event is sent to downstream elements. Most video encoder elements
29 * will insert synchronization points into the stream when this event
30 * is received. When used with a tee element, the scenechange element
31 * can be used to align the synchronization points among multiple
32 * video encoders, which is useful for segmented streaming.
34 * The scenechange element does not work with compressed video.
36 * ## Example launch line
38 * gst-launch-1.0 -v filesrc location=some_file.ogv ! decodebin !
39 * scenechange ! theoraenc ! fakesink
44 * The algorithm used for scene change detection is a modification
45 * of Jim Easterbrook's shot change detector. I'm not aware of a
46 * research paper, but the code I got the idea from is here:
47 * http://sourceforge.net/projects/shot-change/
49 * The method is relatively simple. Calculate the sum of absolute
50 * differences of a picture and the previous picture, and compare this
51 * picture difference value with neighboring pictures. In the original
52 * algorithm, the value is compared to a configurable number of past
53 * and future pictures. However, comparing to future frames requires
54 * introducing latency into the stream, which I did not want. So this
55 * implementation only compared to previous frames.
57 * This code is more directly derived from the scene change detection
58 * implementation in Schroedinger. Schro's implementation is closer
59 * to the Easterbrook algorithm, comparing to future pictures. In
60 * terms of accuracy, schro's implementation has about 2-3 false positives
61 * or false negatives per 100 scene changes. This implementation has
62 * about 5 per 100. The threshold is tuned for minimum total false
63 * positives or negatives, on the assumption that the badness of a
64 * false negative is the same as a false positive.
66 * This algorithm is pretty much at its limit for error rate. I
67 * recommend any future work in this area to increase the complexity
68 * of detection, and then write an automatic tuning system as opposed
69 * to the manual tuning I did here.
71 * Inside the TESTING define are some hard-coded (mostly hand-written)
72 * scene change frame numbers for some easily available sequences.
81 #include <gst/video/video.h>
82 #include <gst/video/gstvideofilter.h>
84 #include "gstscenechange.h"
85 #include "gstscenechangeorc.h"
87 GST_DEBUG_CATEGORY_STATIC (gst_scene_change_debug_category);
88 #define GST_CAT_DEFAULT gst_scene_change_debug_category
93 static GstFlowReturn gst_scene_change_transform_frame_ip (GstVideoFilter *
94 filter, GstVideoFrame * frame);
98 static gboolean is_shot_change (int frame_number);
107 GST_VIDEO_CAPS_MAKE("{ I420, Y42B, Y41B, Y444 }")
109 /* class initialization */
111 G_DEFINE_TYPE_WITH_CODE (GstSceneChange, gst_scene_change,
112 GST_TYPE_VIDEO_FILTER,
113 GST_DEBUG_CATEGORY_INIT (gst_scene_change_debug_category, "scenechange", 0,
114 "debug category for scenechange element"));
115 GST_ELEMENT_REGISTER_DEFINE (scenechange, "scenechange",
116 GST_RANK_NONE, gst_scene_change_get_type ());
119 gst_scene_change_class_init (GstSceneChangeClass * klass)
121 GstVideoFilterClass *video_filter_class = GST_VIDEO_FILTER_CLASS (klass);
123 gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
124 gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
125 gst_caps_from_string (VIDEO_CAPS)));
126 gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
127 gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
128 gst_caps_from_string (VIDEO_CAPS)));
130 gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
131 "Scene change detector",
132 "Video/Filter", "Detects scene changes in video",
133 "David Schleef <ds@entropywave.com>");
135 video_filter_class->transform_frame_ip =
136 GST_DEBUG_FUNCPTR (gst_scene_change_transform_frame_ip);
141 gst_scene_change_init (GstSceneChange * scenechange)
147 get_frame_score (GstVideoFrame * f1, GstVideoFrame * f2)
152 width = f1->info.width;
153 height = f1->info.height;
155 orc_sad_nxm_u8 (&score, f1->data[0], f1->info.stride[0],
156 f2->data[0], f2->info.stride[0], width, height);
158 return ((double) score) / (width * height);
162 gst_scene_change_transform_frame_ip (GstVideoFilter * filter,
163 GstVideoFrame * frame)
165 GstSceneChange *scenechange = GST_SCENE_CHANGE (filter);
166 GstVideoFrame oldframe;
175 GST_DEBUG_OBJECT (scenechange, "transform_frame_ip");
177 if (!scenechange->oldbuf) {
178 scenechange->n_diffs = 0;
179 memset (scenechange->diffs, 0, sizeof (double) * SC_N_DIFFS);
180 scenechange->oldbuf = gst_buffer_ref (frame->buffer);
181 memcpy (&scenechange->oldinfo, &frame->info, sizeof (GstVideoInfo));
186 gst_video_frame_map (&oldframe, &scenechange->oldinfo,
187 scenechange->oldbuf, GST_MAP_READ);
189 GST_ERROR_OBJECT (scenechange, "failed to map old video frame");
190 return GST_FLOW_ERROR;
193 score = get_frame_score (&oldframe, frame);
195 gst_video_frame_unmap (&oldframe);
197 gst_buffer_unref (scenechange->oldbuf);
198 scenechange->oldbuf = gst_buffer_ref (frame->buffer);
199 memcpy (&scenechange->oldinfo, &frame->info, sizeof (GstVideoInfo));
201 memmove (scenechange->diffs, scenechange->diffs + 1,
202 sizeof (double) * (SC_N_DIFFS - 1));
203 scenechange->diffs[SC_N_DIFFS - 1] = score;
204 scenechange->n_diffs++;
206 score_min = scenechange->diffs[0];
207 score_max = scenechange->diffs[0];
208 for (i = 1; i < SC_N_DIFFS - 1; i++) {
209 score_min = MIN (score_min, scenechange->diffs[i]);
210 score_max = MAX (score_max, scenechange->diffs[i]);
213 threshold = 1.8 * score_max - 0.8 * score_min;
215 if (scenechange->n_diffs > (SC_N_DIFFS - 1)) {
218 } else if (score / threshold < 1.0) {
220 } else if ((score > 30)
221 && (score / scenechange->diffs[SC_N_DIFFS - 2] > 1.4)) {
223 } else if (score / threshold > 2.3) {
225 } else if (score > 50) {
234 if (change == TRUE) {
235 memset (scenechange->diffs, 0, sizeof (double) * SC_N_DIFFS);
236 scenechange->n_diffs = 0;
239 if (change != is_shot_change (scenechange->n_diffs)) {
240 g_print ("%d %g %g %g %d\n", scenechange->n_diffs, score / threshold,
241 score, threshold, change);
248 GST_INFO_OBJECT (scenechange, "%d %g %g %g %d",
249 scenechange->n_diffs, score / threshold, score, threshold, change);
252 gst_video_event_new_downstream_force_key_unit (GST_BUFFER_PTS
253 (frame->buffer), GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, FALSE,
254 scenechange->count++);
256 gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (scenechange), event);
268 /* This is from ds's personal collection. No, you can't have it. */
269 int showreel_changes[] = {
270 242, 483, 510, 550, 579, 603, 609, 1056, 1067, 1074, 1079, 1096,
271 1106, 1113, 1127, 1145, 1156, 1170, 1212, 1228, 1243, 1269, 1274,
272 1322, 1349, 1370, 1378, 1423, 1456, 1458, 1508, 1519, 1542, 1679,
273 1767, 1837, 1895, 1962, 2006, 2035, 2102, 2139, 2196, 2561, 2664,
274 2837, 2895, 2985, 3035, 3077, 3128, 3176, 3218, 3306, 3351, 3388,
275 3421, 3470, 3711, 3832, 4029, 4184, 4444, 4686, 4719, 4825, 4941,
276 5009, 5091, 5194, 5254, 5286, 5287, 5343, 5431, 5501, 5634, 5695, 5788,
277 5839, 5861, 5930, 6030, 6168, 6193, 6237, 6336, 6376, 6421, 6495,
278 6550, 6611, 6669, 6733, 6819, 6852, 6944, 7087, 7148, 7189, 7431,
279 7540, 7599, 7632, 7661, 7693, 7930, 7963, 8003, 8076, 8109, 8147,
280 8177, 8192, 8219, 8278, 8322, 8370, 8409, 8566, 8603, 8747, 8775,
281 8873, 8907, 8955, 8969, 8983, 8997, 9026, 9079, 9140, 9165, 9206,
282 9276, 9378, 9449, 9523, 9647, 9703, 9749, 9790, 9929, 10056, 10216,
283 10307, 10411, 10487, 10557, 10695, 10770, 10854, 11095, 11265, 11517, 11589,
284 11686, 11825, 11940, 12004, 12047, 12113, 12179, 12233, 12532, 12586, 12708,
285 12793, 12877, 12954, 13030, 13105, 13177, 13279, 13396, 13486, 13538, 13561,
286 13591, 13627, 13656, 13709, 13763, 13815, 13842, 13876, 13906, 13929, 13955,
287 14003, 14070, 14097, 14127, 14153, 14198, 14269, 14348, 14367, 14440, 14488,
288 14548, 14573, 14599, 14630, 14665, 14907, 14962, 15013, 15089, 15148, 15227,
289 15314, 15355, 15369, 15451, 15470, 15542, 15570, 15640, 15684, 15781, 15869,
290 15938, 16172, 16266, 16429, 16479, 16521, 16563, 16612, 16671, 16692, 16704,
291 16720, 16756, 16789, 16802, 16815, 16867, 16908, 16939, 16953, 16977, 17006,
292 17014, 17026, 17040, 17062, 17121, 17176, 17226, 17322, 17444, 17496, 17641,
293 17698, 17744, 17826, 17913, 17993, 18073, 18219, 18279, 18359, 18475, 18544,
294 18587, 18649, 18698, 18756, 18826, 18853, 18866, 19108, 19336, 19481, 19544,
295 19720, 19816, 19908, 19982, 20069, 20310, 20355, 20374, 20409, 20469, 20599,
296 20607, 20652, 20805, 20822, 20882, 20982, 21029, 21433, 21468, 21561, 21602,
297 21661, 21720, 21909, 22045, 22166, 22225, 22323, 22362, 22433, 22477, 22529,
298 22571, 22617, 22642, 22676, 22918, 22978, 23084, 23161, 23288, 23409, 23490,
299 23613, 23721, 23815, 24131, 24372, 24468, 24507, 24555, 24568, 24616, 24634,
300 24829, 24843, 24919, 24992, 25040, 25160, 25288, 25607, 25684, 25717, 25764,
301 25821, 25866, 25901, 25925, 25941, 25978, 25998, 26011, 26030, 26055, 26118,
302 26133, 26145, 26159, 26175, 26182, 26195, 26205, 26238, 26258, 26316, 26340,
303 26581, 26725, 26834, 26874, 26995, 27065, 27178, 27238, 27365, 27607, 27669,
305 27774, 27800, 27841, 27930, 27985, 28057, 28091, 28132, 28189, 28270, 28545,
306 28653, 28711, 28770, 28886, 28966, 29139, 29241, 29356, 29415, 29490, 29576,
307 29659, 29776, 29842, 29910, 30029, 30056, 30100, 30129, 30175, 30316, 30376,
308 30441, 30551, 30666, 30784, 30843, 30948, 31045, 31286, 31315, 31534, 31607,
310 31817, 31853, 31984, 32009, 32112, 32162, 32210, 32264
314 int sintel_changes[] = {
315 752, 1018, 1036, 1056, 1078, 1100, 1169, 1319, 1339, 1370,
316 1425, 1455, 1494, 1552, 1572, 1637, 1663, 1777, 1955, 2060,
317 2125, 2429, 2624, 2780, 2835, 2881, 2955, 3032, 3144, 3217,
318 3315, 3384, 3740, 3890, 4234, 4261, 4322, 4368, 4425, 4481,
319 4555, 4605, 4671, 4714, 4743, 4875, 4920, 5082, 5158, 5267,
320 5379, 5956, 6021, 6071, 6112, 6139, 6221, 6318, 6374, 6519,
321 6558, 6615, 6691, 6803, 6900, 6944, 7134, 7266, 7351, 7414,
322 7467, 7503, 7559, 7573, 7656, 7733, 7876, 7929, 7971, 7985,
323 8047, 8099, 8144, 8215, 8394, 8435, 8480, 9133, 9190, 9525,
327 /* Breathe Out video, http://media.xiph.org/video/misc/ */
328 int breatheout_changes[] = {
329 143, 263, 334, 426, 462, 563, 583, 618, 655, 707,
330 818, 823, 858, 913, 956, 977, 999, 1073, 1124, 1144,
331 1166, 1187, 1206, 1227, 1240, 1264, 1289, 1312, 1477, 1535,
332 1646, 1692, 1739, 1757, 1798, 1855, 1974, 2048, 2129, 2212,
333 2369, 2412, 2463, 2578, 2649, 2699, 2778, 2857, 2923, 3014,
334 3107, 3246, 3321, 3350, 3459, 3498, 3541, 3567, 3613, 3636,
335 3673, 3709, 3747, 3834, 3862, 3902, 3922, 4022, 4117, 4262,
336 4303, 4357, 4556, 4578, 4617, 4716, 4792, 4873, 4895, 4917,
337 4932, 4972, 5015, 5034, 5058, 5090, 5162, 5180, 5202, 5222,
338 5239, 5258, 5281, 5298, 5397, 5430,
339 485, 507, 534, 665, 685, 755, 1023, 1379, 1441, 1503,
340 1584, 1621, 1903, 2081, 2281, 2511, 2958, 3071, 3185, 3214,
341 3271, 3424, 3479, 3588, 3879, 3979, 4043, 4062, 4143, 4207,
342 4237, 4336, 4461, 4476, 4533, 4647, 4815, 4853, 4949, 5075,
344 3514, 3952, 4384, 5337
347 #define changes showreel_changes
350 is_shot_change (int frame_number)
353 for (i = 0; i < sizeof (changes) / sizeof (changes[0]); i++) {
354 if (changes[i] == frame_number)