Procházet zdrojové kódy

视频分段相似识别完成

DevYK před 3 roky
rodič
revize
16588da7bd

binární
java/out/production/java/com/bytesflow/opencv/media/jni/PQCVMediaProcessor.class


+ 3 - 1
java/src/com.bytesflow.opencv.media/jni/PQCVMediaProcessor.java

@@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap;
 /**
  * 输出头文件步骤
  * cd out/production/jni
- * 执行: javah com.bytesflow.media.jni.PQCVMediaProcessor
+ * 执行: javah com.bytesflow.opencv.media.jni.PQCVMediaProcessor
  */
 public class PQCVMediaProcessor {
 
@@ -29,5 +29,7 @@ public class PQCVMediaProcessor {
 
     public native static int blurDetectionFromImagePath(String path);
 
+    public native static String getVideoSimilarityLists(String inputjson);
+
     public native static int blurDetectionFromImageBytes(byte[] data);
 }

+ 16 - 3
jni/ImageBlurDetection.cpp

@@ -4,6 +4,7 @@
 
 #include "ImageBlurDetection.h"
 
+
 static jint Java_JNI_OpenCV_ImagePathBlurDetection(JNIEnv *env, jobject obj, jstring filepath) {
     const char *image_path = env->GetStringUTFChars(filepath, 0);
     int ret = image_blur_detection(image_path);
@@ -11,18 +12,30 @@ static jint Java_JNI_OpenCV_ImagePathBlurDetection(JNIEnv *env, jobject obj, jst
     return ret;
 }
 
+static jstring Java_JNI_OpenCV_GetVideoSimilarityLists(JNIEnv *env, jobject obj, jstring filepath) {
+    const char *image_path = env->GetStringUTFChars(filepath, 0);
+    const char *ret_json = get_video_similarity_list(image_path);
+    env->ReleaseStringUTFChars(filepath, image_path);
+    if (ret_json) {
+        jstring str = env->NewStringUTF(ret_json);
+        return str;
+    }
+    return NULL;
+}
+
 static jint
 Java_JNI_OpenCV_ImageBytesBlurDetection(JNIEnv *env, jobject obj, jbyteArray data) {
     jbyte *image_bytes = env->GetByteArrayElements(data, 0);
-    int ret = bytes_blur_detection((uint8_t *) image_bytes,env->GetArrayLength(data));
+    int ret = bytes_blur_detection((uint8_t *) image_bytes, env->GetArrayLength(data));
     env->ReleaseByteArrayElements(data, image_bytes, 0);
     return ret;
 }
 
 
 static const JNINativeMethod configMethods[] = {
-        {"blurDetectionFromImagePath",  "(Ljava/lang/String;)I", (void **) Java_JNI_OpenCV_ImagePathBlurDetection},
-        {"blurDetectionFromImageBytes", "([B)I",               (void **) Java_JNI_OpenCV_ImageBytesBlurDetection},
+        {"blurDetectionFromImagePath",  "(Ljava/lang/String;)I",                 (void **) Java_JNI_OpenCV_ImagePathBlurDetection},
+        {"blurDetectionFromImageBytes", "([B)I",                                 (void **) Java_JNI_OpenCV_ImageBytesBlurDetection},
+        {"getVideoSimilarityLists",     "(Ljava/lang/String;)Ljava/lang/String", (void **) Java_JNI_OpenCV_GetVideoSimilarityLists}
 };
 
 

+ 2 - 1
jni/ImageBlurDetection.h

@@ -2,7 +2,8 @@
 // Created by 阳坤 on 2022/2/23.
 //
 #include "jni.h"
-#include "../src/detection/image_blur_detection.h"
+#include "../src/opencv/image_blur_detection.h"
+#include "../src/utils/video_similarity.h"
 #ifndef LOPENCVSAMPLE_IMAGEBLURDETECTION_H
 #define LOPENCVSAMPLE_IMAGEBLURDETECTION_H
 

+ 1 - 2
src/ffmpeg/av_decode.cpp

@@ -344,7 +344,7 @@ int av_read_decode_frame(long decodec_id) {
 void *av_read_decode_thread(void *pVoid) {
     int ret = 0;
     if (pVoid) {
-        struct DecoderContext *ctx = (struct DecoderContext *) pVoid;
+        auto *ctx = (struct DecoderContext *) pVoid;
         if (ctx && ctx->avformatContext) {
             for (const auto &cur_item : ctx->vs_decodes) {
                 //init
@@ -414,5 +414,4 @@ void *av_read_decode_thread(void *pVoid) {
         ctx->video_queue->PushBack(NULL);
     }
     pthread_exit(NULL);
-    return 0;
 }

+ 7 - 5
src/ffmpeg/av_tools.h

@@ -82,6 +82,12 @@ static inline void split(char *str_, char delims[], long ret[], int *count) {
     *count = index;
 }
 
+static inline long getCurrentTimeMills() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
 static inline void Log(const char *format, ...) {
     char szBuffer[1024] = {0};
     char szTime[1024] = {0};
@@ -112,11 +118,7 @@ static inline void Log(const char *format, ...) {
     printf("%s\n", szBuffer);
 }
 
-static inline long getCurrentTimeMills() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
+
 
 static int getVideoRotate(AVDictionary *metadata);
 

+ 20 - 1
src/utils/video_similarity.cpp

@@ -162,6 +162,25 @@ const char *videoSimilarity2json(VideoSimilarity *videoSimilarity) {
     const char *ret_json = strdup(json_file.c_str());
 
     videoSimilarity->clips.clear();
-    delete videoSimilarity;
+    return ret_json;
+}
+
+/**
+ * 获取视频相似值列表
+ * @param inputfile
+ * @return
+ */
+const char *get_video_similarity_list(const char *inputjson) {
+    auto *vs = json2VideoSimilarity(inputjson);
+    long id = video_similarity_detection_init(vs->videoPath);
+    const char * ret_json = NULL;
+    if (id > 0) {
+        video_similarity_detection_start(id, 0, AUDIO,
+                                                   &vs->clips);
+        video_similarity_detection_close(id);
+        ret_json = videoSimilarity2json(vs);
+        delete vs;
+        vs = NULL;
+    }
     return ret_json;
 }

+ 4 - 0
src/utils/video_similarity.h

@@ -54,4 +54,8 @@ int video_similarity_detection_start(long id, int force_keyframe,
  */
 int video_similarity_detection_close(long id);
 
+
+
+const char * get_video_similarity_list(const char * inputfile);
+
 #endif //BYTESFLOW_OPENCV_MEDIA_VIDEO_SIMILARITY_H

+ 146 - 54
src/video_similarity_comparison.cpp

@@ -18,7 +18,7 @@ typedef struct VsimBean {
     pthread_t id;
 } VsimBean;
 
-static void run(const char * filepath,std::vector<VideoSimilarityModel *> *list){
+static void run(const char *filepath, std::vector<VideoSimilarityModel *> *list) {
     long id = video_similarity_detection_init(filepath);
     if (id > 0) {
         int ret = video_similarity_detection_start(id, 0, AUDIO,
@@ -32,11 +32,30 @@ static void run(const char * filepath,std::vector<VideoSimilarityModel *> *list)
 
 static void *run_thread(void *p) {
     auto *vsimBean = (VsimBean *) p;
-    run(vsimBean->filepath,&vsimBean->lists);
+    run(vsimBean->filepath, &vsimBean->lists);
     return 0;
 }
 
 
+static int *list_sim_compare(std::vector<ImageHashModel *> a, std::vector<ImageHashModel *> b) {
+    int minFrames = MIN(a.size(), b.size());
+    int maxFrames = MAX(a.size(), b.size());
+    int sim_frame_count = 0;
+    int arr[2];
+    //比较帧指纹
+    for (int k = 0; k < minFrames; ++k) {
+        float v_sim = fingerprint_compare(a[k]->image_hash, b[k]->image_hash,
+                                          minFrames);
+        if (v_sim > 0.90) {
+            sim_frame_count++;
+        }
+    }
+    arr[0] = sim_frame_count;
+    arr[1] = maxFrames;
+    return arr;
+}
+
+
 /**
  * 1、判断比对文件的 MD5 是否相等
  *  1.1、如果相等,
@@ -52,17 +71,17 @@ int main(int argc, char *argv[]) {
     const char *input_json = "{\n"
                              "    \"videoPath\": \"/Users/devyk/Data/Project/sample/github_code/OpenCVSample/temp/19581045gIiFKepxbbplF3XtsG\",\n"
                              "    \"clips\": [\n"
-//                             "        {\n"
-//                             "            \"startTimeMs\": 0,\n"
-//                             "            \"endTimeMs\": 5000\n"
-//                             "        },\n"
                              "        {\n"
                              "            \"startTimeMs\": 0,\n"
-                             "            \"endTimeMs\": 50\n"
+                             "            \"endTimeMs\": 1000\n"
+                             "        },\n"
+                             "        {\n"
+                             "            \"startTimeMs\": 2000,\n"
+                             "            \"endTimeMs\": 3000\n"
                              "        },\n"
                              "        {\n"
-                             "            \"startTimeMs\": 600000,\n"
-                             "            \"endTimeMs\": 610000\n"
+                             "            \"startTimeMs\": 5000,\n"
+                             "            \"endTimeMs\": 5500\n"
                              "        }\n"
                              "    ]\n"
                              "}";
@@ -83,75 +102,148 @@ int main(int argc, char *argv[]) {
 //                           "    ]\n"
 //                           "}";
 
-    auto vs = json2VideoSimilarity(input_json);
+//    auto vs = json2VideoSimilarity(input_json);
 //    auto json = videoSimilarity2json(vs);
 
     int32_t size = 7;
     const char *filepath[size];
     //票圈视频iOS客户端上传
-    filepath[0] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220304/20820121YCuumFJkPsqfRo51So";
+    filepath[0] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220309/17025689Igao51Q0IMBYw8aNKH";
     //ios 原生上传
-    filepath[1] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220304/20820121sxPL3akcURUIHquge3";
+    filepath[1] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220309/17025689VvI5KURrrxzlZ0Kcdv";
     //iOS h5上传
-    filepath[2] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220304/20820121rm4gHAdXW1IBr1ASEM";
+    filepath[2] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220309/17025689iBy9WFswYdBNblY9au";
     //票圈视频安卓客户端上传
-    filepath[3] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220304/200908721BH3GFTuCyThA6LMBY";
+    filepath[3] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220309/17677590exDXG6q75ELejK7aMY";
     //安卓h5上传
-    filepath[4] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220304/20090872465XAee2WXc6Pjz55z";
+    filepath[4] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220309/176775906GoWtUCYoVZYDbO1XX";
     //安卓原生上传
-    filepath[5] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220304/20090872DaWq15NTiSgmJvMNwC";
+    filepath[5] = "";
+    //PC 上传
+    filepath[5] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220309/17025689nSyGzifJFr4Apl0zc8";
 //    filepath[5] = "http://rescdn.yishihui.com/longvideo/video/vpc/20220304/20090872TkYCoGR785GKZPPM7K";
     http://rescdn.yishihui.com/longvideo/video/vpc/20220304/17938576TxEh0UJXpzcoYRJuHu
     //本地 local 上传的视频
-    filepath[6] = "/Users/devyk/Downloads/share_18b774aab823c23d8072d7c45f8b9636.MP4";
+    filepath[6] = "/Users/devyk/Data/Project/sample/github_code/OpenCVSample/temp/19581045gIiFKepxbbplF3XtsG.mp4";
+
+//    run(vs->videoPath,&vs->clips);
 
+//    const char * ret = videoSimilarity2json(vs);
 
-    run(vs->videoPath,&vs->clips);
+//    const char *local_url = "/Users/devyk/Data/Project/sample/github_code/OpenCVSample/temp/19581045gIiFKepxbbplF3XtsG.mp4";
+//    std::vector<VideoSimilarityModel *> local_list;
+//    run(local_url, &local_list);
 
-    const char * ret = videoSimilarity2json(vs);
-    LOGE("ret =%s \n",ret);
-    free((void*)ret);
-    return 1;
+    std::vector<VideoSimilarityModel *> lists[size];
+    int split_count = 10;
+//    int total = 3960000;
+    int ii = 1000 * 60*6;
 
-    VsimBean vsimBean[size];
+    int start = ii;
     for (int i = 0; i < size; ++i) {
-        vsimBean[i].filepath = strdup(filepath[i]);
-//        vsimBean[i].lists = vs->clips[i];
-        pthread_create(&vsimBean[i].id, 0, run_thread, &vsimBean[i]);
+        auto start_time = getCurrentTimeMills();
+        start = ii;
+        for (int j = 0; j < split_count; ++j) {
+            if (j == 0 || j == split_count-1) {
+                continue;
+            }
+            auto *item = new VideoSimilarityModel();
+            item->startTimeMs = start;
+            item->endTimeMs = item->startTimeMs + 1000;
+            lists[i].push_back(item);
+            start+=ii;
+        }
+        LOGE(">>>filepath=%s \n", filepath[i]);
+        run(filepath[i], &lists[i]);
+        LOGE("<<<filepath=%s cost time=%lld \n", filepath[i], getCurrentTimeMills() - start_time);
     }
-    for (int i = 0; i < size; ++i) {
-        pthread_join(vsimBean[i].id, 0);
-        LOGE("################# path=%s size=%d \n", vsimBean[i].filepath, vsimBean[i].lists.size());
+
+    //本地 local
+    std::vector<VideoSimilarityModel *> local = lists[size - 1];
+    int *total_sim[size - 1];
+
+    //本地检查的结果
+//    for (int i = 0; i < local.size(); ++i) {
+    //第 i 本地层的 hashs
+//        std::vector<ImageHashModel *> local_hashs = local[i]->hashs;
+
+    //对比的视频 size
+
+
+    int test_vis[6][10] = {0};
+    int test_vis_total[6][10] = {0};
+    for (int j = 0; j < size - 1; ++j) {
+        for (int g = 0; g < lists[j].size(); ++g) {
+            int *cur_sim = list_sim_compare(local[g]->hashs, lists[j][g]->hashs);
+            int a = cur_sim[0];
+            int b  = cur_sim[1];
+            test_vis[j][g] = a;
+            test_vis_total[j][g] = b;
+        }
+
+//        int *cur_sim = list_sim_compare(local[0]->hashs, lists[j][0]->hashs);
+//        int a = cur_sim[0];
+//        int b  = cur_sim[1];
+//        test_vis[j][0] = a;
+//        test_vis_total[j][0] = b;
+
+    }
+//    LOGE("相似度 = %f \n", sim_v * 1.0 / total_v * 1.0);
+
+    for (int i = 0; i <size-1; ++i) {
+        int a_t = 0,b_t = 0;
+        for (int j = 0; j < 8; ++j) {
+            a_t += test_vis[i][j];
+            b_t += test_vis_total[i][j];
+        }
+        LOGE("%s %s 相似度 = %f \n", filepath[6],filepath[i],a_t*1.0/b_t*1.0);
     }
+    printf("");
+
+//    const char *ret = get_video_similarity_list(input_json);
+//    printf("ret =%s \n", ret);
+//    free((void *) ret);
+//    return 1;
+
+//    VsimBean vsimBean[size];
+//    for (int i = 0; i < size; ++i) {
+//        vsimBean[i].filepath = strdup(filepath[i]);
+////        vsimBean[i].lists = vs->clips[i];
+//        pthread_create(&vsimBean[i].id, 0, run_thread, &vsimBean[i]);
+//    }
+//    for (int i = 0; i < size; ++i) {
+//        pthread_join(vsimBean[i].id, 0);
+//        LOGE("################# path=%s size=%d \n", vsimBean[i].filepath, vsimBean[i].lists.size());
+//    }
 
     //开始比较
 //    for (int i = 0; i < size; ++i) {
-    for (int i = 0; i < 1; ++i) {
-        auto a = vsimBean[6];
-        for (int j = i; j < size - 1; ++j) {
-            auto b = vsimBean[j];
-            //比较 md5
-//            if (md5_is_exactly_the_same(a.image_md5, b.image_md5) == 0) {
-//                LOGE("path1=%s path2=%s MD5 完全相似\n", a.filepath, b.filepath);
-//                continue;
-//            } else {
-//                LOGE("path1=%s path2=%s MD5 完全不相似\n", a.filepath, b.filepath);
+//    for (int i = 0; i < 1; ++i) {
+//        auto a = vsimBean[6];
+//        for (int j = i; j < size - 1; ++j) {
+//            auto b = vsimBean[j];
+//            //比较 md5
+////            if (md5_is_exactly_the_same(a.image_md5, b.image_md5) == 0) {
+////                LOGE("path1=%s path2=%s MD5 完全相似\n", a.filepath, b.filepath);
+////                continue;
+////            } else {
+////                LOGE("path1=%s path2=%s MD5 完全不相似\n", a.filepath, b.filepath);
+////            }
+//            int minFrames = MIN(a.lists.size(), b.lists.size());
+//            int maxFrames = MAX(a.lists.size(), b.lists.size());
+//            int sim_frame_count = 0;
+//            //比较帧指纹
+//            for (int k = 0; k < minFrames; ++k) {
+//                float v_sim = fingerprint_compare(a.lists[k]->image_hash, b.lists[k]->image_hash,
+//                                                  MIN(a.lists[k]->img_len, b.lists[k]->img_len));
+//                if (v_sim > 0.90) {
+//                    sim_frame_count++;
+//                }
 //            }
-            int minFrames = MIN(a.lists.size(), b.lists.size());
-            int maxFrames = MAX(a.lists.size(), b.lists.size());
-            int sim_frame_count = 0;
-            //比较帧指纹
-            for (int k = 0; k < minFrames; ++k) {
-                float v_sim = fingerprint_compare(a.lists[k]->image_hash, b.lists[k]->image_hash,
-                                                  MIN(a.lists[k]->img_len, b.lists[k]->img_len));
-                if (v_sim > 0.90) {
-                    sim_frame_count++;
-                }
-            }
-            LOGE("path1=%s path2=%s 相似度=%f   \n", a.filepath, b.filepath,
-                 (float) sim_frame_count / (float) maxFrames);
-        }
-    }
+//            LOGE("path1=%s path2=%s 相似度=%f   \n", a.filepath, b.filepath,
+//                 (float) sim_frame_count / (float) maxFrames);
+//        }
+//    }
 
     LOGE("end \n");
     return 0;