#include "downscale.hpp" #include extern "C" { #include #include } #include #include static raw_rgb_image downscale_step(AVFrame const * frame, int factor) { raw_rgb_image image(frame->width / factor, frame->height / factor); auto context = sws_getContext(frame->width, frame->height, static_cast(frame->format), image.width(), image.height(), image.format(), 0, nullptr, nullptr, nullptr); if(!context) throw std::runtime_error("boem sws context"); sws_scale (context, {frame->data}, {frame->linesize}, 0, frame->height, {image.frame->data}, {image.frame->linesize}); sws_freeContext(context); return image; } static raw_rgb_image downscale_to(const av::frame &frame, int w, int h){ // ffmpeg doesnt let us downscale all the way to 5 at once :(, so we do a loop raw_rgb_image image; auto new_frame = frame.get(); while(new_frame->width > 8*w && new_frame->height > 8*h){ image = downscale_step(new_frame, 4); new_frame = image.frame.get(); } return to_raw_rgb_image(image.frame, w, h); } downscale downscale::pre_calculate(av::frame const & frame){ auto const image = downscale_to(crop_to_square(frame), 5, 5); downscale ret; ret.data.assign(image.data.size(), 0); std::copy(image.data.begin(), image.data.end(), ret.data.begin()); return ret; } downscale downscale::calculate(const av::frame& frame){ return pre_calculate(frame); } static double square(double x){ return x*x; } double downscale::distance_to(const downscale& fingerprint) const { assert(data.size() == fingerprint.data.size()); double distance = 0; for(size_t i = 0; i < data.size(); ++i){ distance += square(data[i] - fingerprint.data[i]); } return distance; }