static GstFlowReturn gst_scene_change_filter_ip_I420 (GstVideoFilter2 * videofilter2, GstBuffer * buf, int start, int end) { GstSceneChange *scenechange; double score_min; double score_max; double threshold; double score; gboolean change; int i; int width; int height; g_return_val_if_fail (GST_IS_SCENE_CHANGE (videofilter2), GST_FLOW_ERROR); scenechange = GST_SCENE_CHANGE (videofilter2); width = GST_VIDEO_FILTER2_WIDTH (videofilter2); height = GST_VIDEO_FILTER2_HEIGHT (videofilter2); if (!scenechange->oldbuf) { scenechange->n_diffs = 0; memset (scenechange->diffs, 0, sizeof (double) * SC_N_DIFFS); scenechange->oldbuf = gst_buffer_ref (buf); return GST_FLOW_OK; } score = get_frame_score (GST_BUFFER_DATA (scenechange->oldbuf), GST_BUFFER_DATA (buf), width, height); memmove (scenechange->diffs, scenechange->diffs + 1, sizeof (double) * (SC_N_DIFFS - 1)); scenechange->diffs[SC_N_DIFFS - 1] = score; scenechange->n_diffs++; gst_buffer_unref (scenechange->oldbuf); scenechange->oldbuf = gst_buffer_ref (buf); score_min = scenechange->diffs[0]; score_max = scenechange->diffs[0]; for (i = 1; i < SC_N_DIFFS - 1; i++) { score_min = MIN (score_min, scenechange->diffs[i]); score_max = MAX (score_max, scenechange->diffs[i]); } threshold = 1.8 * score_max - 0.8 * score_min; if (scenechange->n_diffs > 2) { if (score < 5) { change = FALSE; } else if (score / threshold < 1.0) { change = FALSE; } else if (score / threshold > 2.5) { change = TRUE; } else if (score > 50) { change = TRUE; } else { change = FALSE; } } else { change = FALSE; } #ifdef TESTING if (change != is_shot_change (scenechange->n_diffs)) { g_print ("%d %g %g %g %d\n", scenechange->n_diffs, score / threshold, score, threshold, change); } #endif if (change) { GstEvent *event; GST_DEBUG_OBJECT (scenechange, "%d %g %g %g %d", scenechange->n_diffs, score / threshold, score, threshold, change); event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, gst_structure_new ("GstForceKeyUnit", NULL)); gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (scenechange), event); } return GST_FLOW_OK; }
static GstFlowReturn gst_scene_change_transform_frame_ip (GstVideoFilter * filter, GstVideoFrame * frame) { GstSceneChange *scenechange = GST_SCENE_CHANGE (filter); GstVideoFrame oldframe; double score_min; double score_max; double threshold; double score; gboolean change; gboolean ret; int i; GST_DEBUG_OBJECT (scenechange, "transform_frame_ip"); if (!scenechange->oldbuf) { scenechange->n_diffs = 0; memset (scenechange->diffs, 0, sizeof (double) * SC_N_DIFFS); scenechange->oldbuf = gst_buffer_ref (frame->buffer); memcpy (&scenechange->oldinfo, &frame->info, sizeof (GstVideoInfo)); return GST_FLOW_OK; } ret = gst_video_frame_map (&oldframe, &scenechange->oldinfo, scenechange->oldbuf, GST_MAP_READ); if (!ret) { GST_ERROR_OBJECT (scenechange, "failed to map old video frame"); return GST_FLOW_ERROR; } score = get_frame_score (&oldframe, frame); gst_video_frame_unmap (&oldframe); gst_buffer_unref (scenechange->oldbuf); scenechange->oldbuf = gst_buffer_ref (frame->buffer); memcpy (&scenechange->oldinfo, &frame->info, sizeof (GstVideoInfo)); memmove (scenechange->diffs, scenechange->diffs + 1, sizeof (double) * (SC_N_DIFFS - 1)); scenechange->diffs[SC_N_DIFFS - 1] = score; scenechange->n_diffs++; score_min = scenechange->diffs[0]; score_max = scenechange->diffs[0]; for (i = 1; i < SC_N_DIFFS - 1; i++) { score_min = MIN (score_min, scenechange->diffs[i]); score_max = MAX (score_max, scenechange->diffs[i]); } threshold = 1.8 * score_max - 0.8 * score_min; if (scenechange->n_diffs > 2) { if (score < 5) { change = FALSE; } else if (score / threshold < 1.0) { change = FALSE; } else if (score / threshold > 2.5) { change = TRUE; } else if (score > 50) { change = TRUE; } else { change = FALSE; } } else { change = FALSE; } #ifdef TESTING if (change != is_shot_change (scenechange->n_diffs)) { g_print ("%d %g %g %g %d\n", scenechange->n_diffs, score / threshold, score, threshold, change); } #endif if (change) { GstEvent *event; GST_INFO_OBJECT (scenechange, "%d %g %g %g %d", scenechange->n_diffs, score / threshold, score, threshold, change); event = gst_video_event_new_downstream_force_key_unit (GST_BUFFER_PTS (frame->buffer), GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, FALSE, scenechange->count++); gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (scenechange), event); } return GST_FLOW_OK; }