video_similarity.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. //
  2. // Created by 阳坤 on 2022/3/1.
  3. //
  4. #include <json/reader.h>
  5. #include <json/writer.h>
  6. #include "video_similarity.h"
  7. long video_similarity_detection_init(const char *url) {
  8. auto *ctx = (VideoSimilarityContext *) malloc(sizeof(VideoSimilarityContext));
  9. if (!ctx)return -1;
  10. memset(ctx, 0, sizeof(VideoSimilarityContext));
  11. ctx->video_path = strdup(url);
  12. return (long) ctx;
  13. }
  14. static const char *GetFileName(const char *ptr, int n) {
  15. int i = n; //这里i只是为循环即使终止了也未找到/而准备
  16. ptr += n; //把指针移到字符串的尾部,即'\0'处
  17. while (i-- > 0) {
  18. if ((*ptr--) == '/') //指针不断回移并判断是否为/符号
  19. {
  20. break; //从后向前遇到第一个/后退出循环
  21. }
  22. }
  23. ptr += 2;
  24. return ptr; //反回最后一个/后面的字符串即名称
  25. }
  26. int video_similarity_detection_start(long id, int force_keyframe,
  27. DisableMediaType disableMediaType,
  28. std::vector<VideoSimilarityModel *> *lists) {
  29. if (id <= 0)return -1;
  30. auto *ctx = (VideoSimilarityContext *) id;
  31. long d_id = initDecoder(ctx->video_path, force_keyframe, disableMediaType);
  32. ctx->decode_obj_id = d_id;
  33. if (ctx->decode_obj_id <= 0)return ctx->decode_obj_id;
  34. int exit = 0, ret = 0;
  35. av_read_decode_frame(ctx->decode_obj_id);
  36. auto *dctx = (DecoderContext *) ctx->decode_obj_id;
  37. dctx->vs_decodes = *lists;
  38. int index = 0;
  39. auto endTimeMs = (*lists)[index]->endTimeMs;
  40. while (!exit) {
  41. AVFrame *video_frame = NULL;
  42. dctx->video_queue->PopFront(video_frame);
  43. if (video_frame == NULL) {
  44. LOGE("read video frame end.");
  45. break;
  46. }
  47. int len = 0;
  48. const char *image_hash = fingerprintFromFFAVFrame(ctx->log, video_frame, &len);
  49. if (len > 64) {
  50. LOGE("size=%d \n", len);
  51. }
  52. auto *model = (ImageHashModel *) malloc(sizeof(ImageHashModel));
  53. memset(model, 0, sizeof(ImageHashModel));
  54. model->img_len = len;
  55. if (len > 0) {
  56. model->image_hash = static_cast<const char *>(malloc(sizeof(char) * len));
  57. memcpy((void *) model->image_hash, image_hash, len);
  58. }
  59. if (video_frame->pts >= endTimeMs && (*lists).size() > 1 && index + 1 < (*lists).size()) {
  60. index++;
  61. endTimeMs = (*lists)[index]->endTimeMs;
  62. }
  63. model->pts = video_frame->pts;
  64. // LOGE("push pts >>>>= %lld \n", model->pts);
  65. (*lists)[index]->hashs.push_back(model);
  66. fprintf(ctx->log, "image_hash ");
  67. if (image_hash)
  68. free((void *) image_hash);
  69. fprintf(ctx->log, "image_hash 2");
  70. av_frame_free(&video_frame);
  71. }
  72. return 0;
  73. }
  74. int video_similarity_detection_close(long id) {
  75. if (id <= 0)return -1;
  76. auto *ctx = (VideoSimilarityContext *) id;
  77. if (ctx->video_path) {
  78. free((void *) ctx->video_path);
  79. ctx->video_path = NULL;
  80. }
  81. if (ctx->log) {
  82. fclose(ctx->log);
  83. ctx->log = NULL;
  84. }
  85. close_decoder(ctx->decode_obj_id);
  86. free(ctx);
  87. ctx = NULL;
  88. return 0;
  89. }
  90. VideoSimilarity *json2VideoSimilarity(const char *json) {
  91. VideoSimilarity *videoSimilarity;
  92. videoSimilarity = new VideoSimilarity();
  93. Json::Reader reader;
  94. Json::Value value;
  95. if (reader.parse(json, value)) {
  96. Json::Value json_obj = value;
  97. if (json_obj.isMember("videoPath"))
  98. videoSimilarity->videoPath = strdup(json_obj["videoPath"].asString().c_str());
  99. if (json_obj.isMember("clips") && json_obj["clips"].type() == Json::arrayValue) {
  100. for (int i = 0; i < json_obj["clips"].size(); ++i) {
  101. auto *videoSim = (VideoSimilarityModel *) malloc(sizeof(VideoSimilarityModel));
  102. memset(videoSim, 0, sizeof(VideoSimilarityModel));
  103. videoSim->startTimeMs = json_obj["clips"][i]["startTimeMs"].asInt();
  104. videoSim->endTimeMs = json_obj["clips"][i]["endTimeMs"].asInt();
  105. videoSimilarity->clips.push_back(videoSim);
  106. }
  107. }
  108. }
  109. return videoSimilarity;
  110. }
  111. const char *videoSimilarity2json(VideoSimilarity *videoSimilarity) {
  112. if (!videoSimilarity)return NULL;
  113. Json::Value obj;
  114. Json::Value array;
  115. Json::StreamWriterBuilder builder;
  116. if (videoSimilarity->videoPath) {
  117. obj["videoPath"] = videoSimilarity->videoPath;
  118. free((void *) videoSimilarity->videoPath);
  119. videoSimilarity->videoPath = NULL;
  120. }
  121. for (auto it = videoSimilarity->clips.begin();
  122. it != videoSimilarity->clips.end();) {
  123. auto item = *it;
  124. Json::Value v;
  125. Json::Value v_array;
  126. v["startTimeMs"] = item->startTimeMs;
  127. v["endTimeMs"] = item->endTimeMs;
  128. for (auto it2 = item->hashs.begin();
  129. it2 != item->hashs.end();) {
  130. ImageHashModel *item2 = *it2;
  131. Json::Value va;
  132. if (item->hashs.size() <= 1499) {
  133. // LOGE("size=%d %d\n", item->hashs.size(), item2->img_len);
  134. }
  135. if (item2->image_hash && item2->img_len > 0) {
  136. string append_array;
  137. for (int i = 0; i < item2->img_len; ++i) {
  138. char c = item2->image_hash[i];
  139. if (c == 0) {
  140. append_array.append("0");
  141. } else if (c == 1) {
  142. append_array.append("1");
  143. }
  144. }
  145. va["imageHash"] = append_array.c_str();
  146. free((void *) item2->image_hash);
  147. }
  148. va["hashSize"] = item2->img_len;
  149. va["pts"] = item2->pts;
  150. v_array.append(va);
  151. free(item2);
  152. item2 = NULL;
  153. it2 = item->hashs.erase(it2);
  154. }
  155. v["hashs"] = v_array;
  156. array.append(v);
  157. free(item);
  158. item = NULL;
  159. it = videoSimilarity->clips.erase(it);
  160. }
  161. obj["clips"] = array;
  162. const std::string json_file = Json::writeString(builder, obj);
  163. const char *ret_json = strdup(json_file.c_str());
  164. videoSimilarity->clips.clear();
  165. return ret_json;
  166. }
  167. /**
  168. * 获取视频相似值列表
  169. * @param inputfile
  170. * @return
  171. */
  172. const char *get_video_similarity_list(const char *inputjson) {
  173. if (!inputjson)return NULL;
  174. printf("get_video_similarity_list=%s \n", inputjson);
  175. auto *vs = json2VideoSimilarity(inputjson);
  176. long id = video_similarity_detection_init(vs->videoPath);
  177. const char *ret_json = NULL;
  178. if (id > 0) {
  179. if (!(((VideoSimilarityContext *) id)->log)) {
  180. int n = strlen(((VideoSimilarityContext *) id)->video_path); //计算字符串的长度(包括'\0')
  181. const char *name = GetFileName(((VideoSimilarityContext *) id)->video_path, n); //把字符串及其长度传给函数
  182. printf("%s\n", name); //name就是那个名称,可以输出
  183. char args[512];
  184. // sprintf(args, "/Users/devyk/Data/Project/sample/github_code/OpenCVSample/temp/%s.log","test");
  185. sprintf(args, "/datalog/%s.log", "test");
  186. ((VideoSimilarityContext *) id)->log = fopen(args, "wb+");
  187. printf("args===%s \n", args);
  188. fprintf(((VideoSimilarityContext *) id)->log, inputjson);
  189. }
  190. video_similarity_detection_start(id, 0, AUDIO,
  191. &vs->clips);
  192. video_similarity_detection_close(id);
  193. ret_json = videoSimilarity2json(vs);
  194. delete vs;
  195. vs = NULL;
  196. }
  197. return ret_json;
  198. }