当前位置: 首页 > news >正文

c++ python 共享内存

一、目的

是为了c++来读取并解码传递给python,Python做测试非常方便,c++ 和 python之间必须定好协议,整体使用c++ 来解码,共享内存传递给python

二、主类

主类,串联decoder,注意decoder并没有直接在显存里面穿透,是解码以后传递给内存,从内存传给python

#pragma once#define __STDC_CONSTANT_MACROS
#define SDL_MAIN_HANDLED#include "c_ringbuffer.h"
#include "TThreadRunable.h"
//#include "FFMPEGLibrary.h"
#include "c_script.h"
#include "memshare.h"
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/pixdesc.h>
#include <libavutil/hwcontext.h>
#include <libavutil/opt.h>
#include <libavutil/avassert.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#include "SDL2\SDL.h"
#include "SDL2\sdl_ttf.h"
};
#include <opencv2/opencv.hpp>
#include "c_plug.h"
#include "IO_Thread.h"
//#include  "process.h"#pragma execution_character_set("utf-8")static void SaveRgb2Bmp(char* rgbbuf, int width, int height, char *file)
{BITMAPINFO bitmapinfo;ZeroMemory(&bitmapinfo, sizeof(BITMAPINFO));bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bitmapinfo.bmiHeader.biWidth = width;bitmapinfo.bmiHeader.biHeight = 0 - height;bitmapinfo.bmiHeader.biPlanes = 1;bitmapinfo.bmiHeader.biBitCount = 24;bitmapinfo.bmiHeader.biXPelsPerMeter = 0;bitmapinfo.bmiHeader.biYPelsPerMeter = 0;bitmapinfo.bmiHeader.biSizeImage = width * height;bitmapinfo.bmiHeader.biClrUsed = 0;bitmapinfo.bmiHeader.biClrImportant = 0;BITMAPFILEHEADER bmpHeader;ZeroMemory(&bmpHeader, sizeof(BITMAPFILEHEADER));bmpHeader.bfType = 0x4D42;bmpHeader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);bmpHeader.bfSize = bmpHeader.bfOffBits + width * height * 3;//fopen("", "wb");FILE* fp;fopen_s(&fp, file, "wb");if (fp){fwrite(&bmpHeader, 1, sizeof(BITMAPFILEHEADER), fp);fwrite(&(bitmapinfo.bmiHeader), 1, sizeof(BITMAPINFOHEADER), fp);fwrite(rgbbuf, 1, width*height * 3, fp);fclose(fp);}
}typedef  std::function<void(cv::Mat)> funcmat_process;typedef struct func_process
{//串联函数名称std::string funcname;funcmat_process v_func_callback = NULL;//func_process* next;
}func_process;class c_SDLDrawer 
{int					m_w = 0, m_h = 0;SDL_Window			*screen = NULL;SDL_Renderer		*sdlRenderer = NULL;SDL_Texture			*sdlTexture = NULL;bool m_window_init = false;TTF_Font * _font = NULL;lfringqueue<AVFrame, 20>* v_pframes ;//画布AVFrame * v_canvas_frame = NULL;void draw(uint8_t *data[], int linesize[], int px, int py, int w, int h, int bias){if (sdlTexture == NULL){sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING, px, py);}SDL_UpdateYUVTexture(sdlTexture, NULL,data[0], linesize[0],data[1], linesize[1],data[2], linesize[2]);if (bias != 0){SDL_Rect			sdlRect;//zoom 放大sdlRect.x = bias;sdlRect.y = bias;sdlRect.w = w - 2 * bias;sdlRect.h = h - 2 * bias;// nh;SDL_RenderCopy(sdlRenderer, sdlTexture, &sdlRect, NULL);}else{//SDL_RenderClear(sdlRenderer);SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);}SDL_RenderPresent(sdlRenderer);}//px_l 向左偏移//py_r 向右便宜void drawBGR(uint8_t *data, int w, int h, int px, int py, int drawrect){if (sdlTexture == NULL){sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_BGR24,SDL_TEXTUREACCESS_STREAMING, w, h);}SDL_UpdateTexture(sdlTexture, NULL, data, w * 3);if (v_after_cut.w != 0) // 需要裁剪{if (px != 0 || py != 0) //裁剪后位移{int w_, h_;SDL_GetWindowSize(screen, &w_, &h_);SDL_Rect dstrect = { 0,0,w_,h_ };dstrect.x += px;dstrect.y += py;SDL_RenderClear(sdlRenderer);SDL_RenderCopy(sdlRenderer, sdlTexture, &v_after_cut, &dstrect);}elseSDL_RenderCopy(sdlRenderer, sdlTexture, &v_after_cut, NULL);}else{if (px != 0 || py != 0){int w_, h_;SDL_GetWindowSize(screen, &w_, &h_);SDL_Rect dstrect = { 0,0,w_,h_ };dstrect.x += px;dstrect.y += py;SDL_RenderClear(sdlRenderer);SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &dstrect);}else{SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);}}/*if (px != 0 || py != 0){int w_, h_;SDL_GetWindowSize(screen, &w_, &h_);SDL_Rect dstrect = { 0,0,w_,h_ };dstrect.x += px;dstrect.y += py;SDL_RenderClear(sdlRenderer);SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &dstrect);}else{int res = v_after_cut.w*v_after_cut.h;if (res == 0){SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);}else{SDL_RenderCopy(sdlRenderer, sdlTexture, &v_after_cut, NULL);}}*/SDL_Color color = { 255,255,255,255 };string show = "this is a test钱波";if (drawrect)SDL_RenderDrawRect(this->sdlRenderer, NULL);displayText("this is a test钱波", { 10,10 },color);color = { 255,0,0,255 };displayText("集装箱", { 500,130 },color);SDL_RenderPresent(sdlRenderer);}bool displayText(std::string text, SDL_Point point,SDL_Color color){if (_font == NULL)return false;SDL_Surface * surface = TTF_RenderUTF8_Blended(_font, text.c_str(), color);SDL_Texture * texture = SDL_CreateTextureFromSurface(sdlRenderer, surface);int w = 0, h = 0;TTF_SizeUTF8(_font, text.c_str(), &w, &h);SDL_Rect des = { point.x, point.y, w, h };SDL_RenderCopy(sdlRenderer, texture, NULL, &des);SDL_FreeSurface(surface);SDL_DestroyTexture(texture);return true;
#if 0TTF_SetFontOutline(_font, 1);int w = 0;int h = 0;if ((TTF_SizeText(_font, "SDL_ttf is awesome!", &w, &h) != -1)) {// Print out the width and height of the string if I render it with myFontstd::cout << "Width : " << w << "\nHeight: " << h << std::endl;}else {// Error...}
#endif}public:int func_init(const void* hWnd, lfringqueue<AVFrame, 20>* frame){v_pframes = frame;//v_hwnd = hWnd;if (m_window_init == false){TTF_Init();if (_font == NULL){_font = TTF_OpenFont("./STXIHEI.TTF", 20);if (_font == NULL) //文字渲染出错return -1;}/* 设置字体样式(加粗|斜体)*/TTF_SetFontStyle(_font, TTF_STYLE_BOLD /*| TTF_STYLE_ITALIC*/);SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");//SDL_setenv(SDL_HINT_RENDER_SCALE_QUALITY, "linear", 0);SDL_Init(SDL_INIT_VIDEO);if (hWnd == NULL){screen = SDL_CreateWindow("FF", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,1920, 1000, SDL_WINDOW_SHOWN/* SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE*/);}else{screen = SDL_CreateWindowFrom(hWnd);}if (screen == NULL){//printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());return -1;}sdlRenderer = SDL_CreateRenderer(screen, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);//sdlRenderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED);//SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");m_window_init = true;}//设置画矩形的颜色为红色SDL_SetRenderDrawColor(sdlRenderer,   // 渲染器0,     // 红0,     // 绿0,     // 蓝128);     // 透明值return 0;}//接口函数//w 高度//h 宽度//bias 偏差//int drawrect 是否画外框矩形void func_drawYUV(int w, int h, int bias, int drawrect){AVFrame* frame = NULL;if (v_pframes->dequeue(&frame)){draw(frame->data, frame->linesize, frame->width, frame->height, w, h, bias);av_freep(&frame->data[0]);av_frame_free(&frame);}}//int px x轴方向减去或者加上多少个像素//int py y轴方向减去或者加上多少个像素void func_draw(int px, int py, AVFrame* frame,int drawrect){if (px < 0)v_cutleft = px;//record the left if (px > 0)v_cutright = px; //record the rightif (py < 0)v_cuttop = py;if (py > 0)v_cutbottom = py;drawBGR(frame->data[0], frame->width, frame->height, px, py, drawrect);}int v_cutleft = 0;int v_cutright = 0;//int v_cutleftright = 0;//1 切除left  2 切除right  3 切除左右 int v_cuttop = 0;int v_cutbottom = 0;//int v_cuttopbottom = 0;//1 切除top  2 切除bottom  3 切除上下//裁剪掉黑边后的rect,需要计算SDL_Rect v_after_cut = {0,0,0,0};void func_cut(int windowx,int windowy, int imagew, int imageh){if (v_after_cut.w == 0 || v_after_cut.h == 0){v_after_cut.w = imagew;v_after_cut.h = imageh;}float w_ = (float)windowx;float h_ = (float)windowy;//int w_, h_;//SDL_GetWindowSize(screen, &w_, &h_);//px / ppx = window_w / imagew;if (v_cutleft < 0) //左边需要切除{int tmpx = v_cutleft * imagew;float pp = (float)tmpx / w_ ;pp = 0 - pp;int ppx = (int)(pp + 0.5);//根据比例计算v_after_cut.x += ppx;v_after_cut.w -= ppx;v_cutleft = 0;}if (v_cutright > 0) //右边需要切除{int tmpx = v_cutright * imagew;float pp = (float)tmpx/w_;int ppx = (int)(pp + 0.5);v_after_cut.w -= ppx;v_cutright = 0;}if (v_cuttop < 0) //上边需要切除{float tmpy = float(v_cuttop * imageh);float pp = tmpy / h_;int ppy = (int)(pp+0.5);v_after_cut.y += (0-ppy); v_after_cut.h -= (0-ppy);v_cuttop = 0;}if (v_cutbottom > 0) //下边需要切除{int tmpy = v_cutbottom * imageh;float pp = (float)tmpy / h_;int ppy = (int)(pp + 0.5);v_after_cut.h -= ppy;v_cutbottom = 0;}}void func_restore(){//所有值都恢复v_after_cut = { 0, 0, 0, 0};v_cutleft = 0;v_cutright = 0;v_cuttop = 0;v_cutbottom = 0;}
public://在图像上画上矩形,表示选中状态void func_draw_rect(){SDL_RenderDrawRect(this->sdlRenderer, NULL);}void UnInit(){if (sdlTexture)SDL_DestroyTexture(sdlTexture);if (sdlRenderer)SDL_DestroyRenderer(sdlRenderer);if (screen){SDL_DestroyWindow(screen);//SDL_ShowWindow(_pWindow);//if (_hWnd!=NULL)//	ShowWindow(_hWnd, 1);screen = NULL;}if (_font != NULL) {TTF_CloseFont(_font);_font = NULL;}TTF_Quit();SDL_Quit();}c_SDLDrawer(){}~c_SDLDrawer(){UnInit();}};//SDL_FillRect(gScreenSurface, NULL, SDL_MapRGB(gScreenSurface->format, 0xFF, 0x00, 0x00));static enum AVPixelFormat hw_pix_fmt = AV_PIX_FMT_DXVA2_VLD;static enum AVPixelFormat get_hw_format(AVCodecContext* ctx,const enum AVPixelFormat* pix_fmts)
{const enum AVPixelFormat* p;for (p = pix_fmts; *p != -1; p++) {if (*p == hw_pix_fmt)return *p;}fprintf(stderr, "Failed to get HW surface format.\n");return AV_PIX_FMT_NONE;
}typedef enum enum_record
{enum_record_none,enum_record_write,enum_record_write_lock,enum_record_write_unlock
}enum_record;class c_AVDecoder :public TThreadRunable
{videoInType v_type = en_mode_client; //如rtspAVPixelFormat sourcepf = AV_PIX_FMT_NV12;// AV_PIX_FMT_NV12;// AV_PIX_FMT_YUV420P;AVPixelFormat destpf = AV_PIX_FMT_BGR24; //AV_PIX_FMT_YUV420PAVBufferRef* hw_device_ctx = NULL;lfringqueue<AVFrame, 20>* v_pframes = NULL;struct SwsContext* img_convert_ctx = NULL;AVFormatContext* input_ctx = NULL;//录像AVFormatContext* output_ctx = NULL;//是否已经有关键帧int v_FindKeyPkt = 0;int stream_video_num;int stream_audio_num;AVStream* stream_video = NULL;AVStream* stream_audio = NULL;AVCodecContext* decoder_ctx = NULL;AVCodec* decoder = NULL;AVPacket packet;enum AVHWDeviceType type;//转换成yuv420 或者rgb//默认client模式int v_clientserver = 0;int hw_decoder_init(AVCodecContext* ctx, const enum AVHWDeviceType type){int err = 0;if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type,NULL, NULL, 0)) < 0) {fprintf(stderr, "Failed to create specified HW device.\n");return err;}ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);return err;}int decode_write(AVCodecContext* avctx, AVPacket* packet){AVFrame* frame = NULL, *sw_frame = NULL;AVFrame* tmp_frame = NULL;AVFrame* pFrameDst = NULL;unsigned char* out_buffer = NULL;int ret = 0;ret = avcodec_send_packet(avctx, packet);if (ret < 0) {fprintf(stderr, "Error during decoding\n");return ret;}static int i = 0;while (1) {if (!(frame = av_frame_alloc()) || !(sw_frame = av_frame_alloc())) {fprintf(stderr, "Can not alloc frame\n");ret = AVERROR(ENOMEM);goto fail;}//avctx->get_buffer2ret = avcodec_receive_frame(avctx, frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {av_frame_free(&frame);av_frame_free(&sw_frame);return 0;}else if (ret < 0) {fprintf(stderr, "Error while decoding\n");goto fail;}if (img_convert_ctx == NULL){img_convert_ctx = sws_getContext(avctx->width, avctx->height, sourcepf,avctx->width, avctx->height, destpf, SWS_FAST_BILINEAR, NULL, NULL, NULL);}if (frame->format == hw_pix_fmt) {/* retrieve data from GPU to CPU */sw_frame->format = sourcepf; // AV_PIX_FMT_NV12;// AV_PIX_FMT_YUV420P;// AV_PIX_FMT_NV12;// AV_PIX_FMT_BGR24;// AV_PIX_FMT_YUV420P;if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) {fprintf(stderr, "Error transferring the data to system memory\n");goto fail;}tmp_frame = sw_frame;}elsetmp_frame = frame;pFrameDst = av_frame_alloc();av_image_alloc(pFrameDst->data, pFrameDst->linesize, avctx->width, avctx->height, destpf, 1);sws_scale(img_convert_ctx, tmp_frame->data, tmp_frame->linesize,0, avctx->height, pFrameDst->data, pFrameDst->linesize);pFrameDst->width = avctx->width;pFrameDst->height = avctx->height;if (!v_pframes->enqueue(pFrameDst, 3)){av_freep(&pFrameDst->data[0]);av_frame_free(&pFrameDst);}fail:av_frame_free(&frame);av_frame_free(&sw_frame);if (ret < 0)return ret;}}std::string v_url;std::string v_record_file;//0非录制状态,1录制状态enum_record v_record = enum_record_none;private:int Record_Stream_Add();int Record_Stream_Open();int Record_Stream_Write(AVPacket* pkt);int Record_Stream_Close();int Record_Stream(AVPacket* pkt);
public:void func_init(const char* url, lfringqueue<AVFrame, 20>* frame = NULL){v_url = url;v_pframes = frame;v_clientserver = 0;}int func_record_start(const char* file){int ret = -1;if (file == NULL)return ret;switch (v_record){case enum_record_none:v_record = enum_record_write;v_record_file = file;ret = 0;break;case enum_record_write://正在写,则锁定,需要close//v_record = enum_record_write_lock;ret = -1;break;case enum_record_write_lock://无法修改ret = -2;break;case enum_record_write_unlock: //写完过文件v_record = enum_record_write;v_record_file = file;ret = 0;break;}return ret;}void func_record_close(){if (v_record == enum_record_none)return;if(v_record == enum_record_write)v_record = enum_record_write_lock;return;}//非本线程Run函数启动,其他线程会调用解码函数时需要初始化int func_init(const char* url ,lfringqueue<AVFrame, 20>* frame, int codecID,uint8_t * extradata,int extradatalen){v_url = url;v_pframes = frame;//0 is client mode//1 is server modev_clientserver = 1;decoder = avcodec_find_decoder((AVCodecID)codecID);return 0;}public:int func_cycle(){const char* stype = "dxva2";int ret = 0;type = av_hwdevice_find_type_by_name(stype);if (type == AV_HWDEVICE_TYPE_NONE) {fprintf(stderr, "Device type %s is not supported.\n", stype);fprintf(stderr, "Available device types:");while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)fprintf(stderr, " %s", av_hwdevice_get_type_name(type));fprintf(stderr, "\n");return -1;}/* open the input file *///const char * filename = "h:/video/a.mp4";AVDictionary* opts = NULL;av_dict_set(&opts, "rtsp_transport", "tcp", 0);av_dict_set(&opts, "buffer_size", "2048000", 0);av_dict_set(&opts, "fpsprobesize", "5", 0);//"-probesize 32 "av_dict_set(&opts, "analyzeduration", "5000000", 0);if (avformat_open_input(&input_ctx, v_url.c_str(), NULL, &opts) != 0) {av_dict_free(&opts);fprintf(stderr, "Cannot open input file '%s'\n", v_url.c_str());return -1;}av_dict_free(&opts);if (avformat_find_stream_info(input_ctx, NULL) < 0) {//av_dict_free(&opts);fprintf(stderr, "Cannot find input stream information.\n");return -1;}/* find the video stream information */stream_video_num = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);if (stream_video < 0) {//av_dict_free(&opts);fprintf(stderr, "Cannot find a video stream in the input file\n");return -1;}AVCodec* decoder_audio;stream_audio_num = av_find_best_stream(input_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &decoder_audio, 0);if (stream_audio_num < 0) {//av_dict_free(&opts);fprintf(stderr, "Cannot find a audio stream in the input file\n");}AVStream* stream = input_ctx->streams[stream_video_num];if (!(decoder_ctx = avcodec_alloc_context3(decoder)))return AVERROR(ENOMEM);stream_video = input_ctx->streams[stream_video_num];if (avcodec_parameters_to_context(decoder_ctx, stream_video->codecpar) < 0)return -1;decoder_ctx->get_format = get_hw_format;if (hw_decoder_init(decoder_ctx, type) < 0)return -1;if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) {fprintf(stderr, "Failed to open codec for stream #%u\n", stream_video_num);return -1;}while (ret >= 0) {if ((ret = av_read_frame(input_ctx, &packet)) < 0)break;if (stream_video_num == packet.stream_index){//这里需要更加精确的计算ret = decode_write(decoder_ctx, &packet);}else //音频包等等{}Record_Stream(&packet);av_packet_unref(&packet);if (IsStop())break;}/* flush the decoder */packet.data = NULL;packet.size = 0;ret = decode_write(decoder_ctx, &packet);av_packet_unref(&packet);avcodec_free_context(&decoder_ctx);avformat_close_input(&input_ctx);av_buffer_unref(&hw_device_ctx);return 0;}queue<RTPPacket*> _queue;void push(uint8_t* data,int len){RTPPacket* pkt = new RTPPacket();pkt->data = new uint8_t[len];memcpy(pkt->data,  data,len);pkt->len = len;_mutex.lock();if (_queue.size() > 20){for (int i = 0; i < 20; i++){RTPPacket* pkt = _queue.front();free(pkt->data);free(pkt);_queue.pop();}}_queue.push(pkt);_mutex.unlock();}bool v_keyframemeet = false;//server模式的视频int func_cycle_server2(){const char* stype = "dxva2";type = av_hwdevice_find_type_by_name(stype);if (type == AV_HWDEVICE_TYPE_NONE) {fprintf(stderr, "Device type %s is not supported.\n", stype);fprintf(stderr, "Available device types:");while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)fprintf(stderr, " %s", av_hwdevice_get_type_name(type));fprintf(stderr, "\n");return -1;}for (int i = 0;; i++) {const AVCodecHWConfig* config = avcodec_get_hw_config(decoder, i);if (!config) {fprintf(stderr, "Decoder %s does not support device type %s.\n",decoder->name, av_hwdevice_get_type_name(type));return -1;}if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&config->device_type == type) {hw_pix_fmt = config->pix_fmt;break;}}if (!(decoder_ctx = avcodec_alloc_context3(decoder)))return AVERROR(ENOMEM);decoder_ctx->get_format = get_hw_format;if (hw_decoder_init(decoder_ctx, type) < 0)return -1;int ret = 0;if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) {fprintf(stderr, "Failed to open codec for stream #%u\n", stream_video_num);return -1;}//AVFrame* frame = av_frame_alloc();int v_timeCount = 0;while (1){bool need_sleep = 0;if (_stop == 1){//qDebug()<< "IO thread break out";break;}_mutex.lock();need_sleep = _queue.empty();_mutex.unlock();if (need_sleep) //no packet {std::this_thread::yield(); //让渡线程//std::this_thread::sleep_for(std::chrono::milliseconds(20));//休整20毫秒if (v_timeCount > 50) //连续50次没有收到包{//qDebug()<<"IO thread broken break";v_timeCount = 0;//自动退出线程break;//连续包已破//数据接收不到,发送破包信息}}else{v_timeCount = 0;_mutex.lock();RTPPacket* pkt = _queue.front();//RTP数据包队列_queue.pop();_mutex.unlock();if (!v_keyframemeet){uint8_t* pos = pkt->data;while (!*(pos++));uint8_t flag = (*pos) & 0x1f;if (flag == 0x07)//只能适应h264{v_keyframemeet = 1;AVPacket avpkt;av_init_packet(&avpkt);avpkt.data = pkt->data;avpkt.size = pkt->len;decode_write(decoder_ctx, &avpkt);//decode_write2(decoder_ctx, &avpkt, frame);}}else{AVPacket avpkt;av_init_packet(&avpkt);avpkt.data = pkt->data;avpkt.size = pkt->len;decode_write(decoder_ctx, &avpkt);//decode_write2(decoder_ctx, &avpkt, frame);}free(pkt->data);free(pkt);}}return 0;}int func_get_decode_width(){if (decoder_ctx != NULL)return decoder_ctx->width;return 0;}int func_get_decode_height(){if (decoder_ctx != NULL)return decoder_ctx->height;return 0;}void Run(){while (1){if (IsStop())break;//if (!IsStop())if (v_clientserver == 0)func_cycle();elsefunc_cycle_server2();}}void func_stop(){Stop();Join();}c_AVDecoder(){}~c_AVDecoder(){}
};//串联av decoder
class c_av_func 
{
public:c_av_func(){}~c_av_func(){}
private:std::string v_url;lfringqueue<AVFrame, 20> v_frames;c_SDLDrawer v_drawer;c_AVDecoder v_decoder;//连锁函数,串联std::vector<func_process> v_funcs;std::mutex v_mutex;std::mutex v_mutex_cache;class Lock {private:std::lock_guard<std::mutex> v_lock;//std::unique_lock<std::mutex> m_lock;//	T *m_data;public:inline Lock(c_av_func* parent) : v_lock(parent->v_mutex){}};
private:void func(cv::Mat nmat){Lock lock(this);auto iter = v_funcs.begin();while (iter != v_funcs.end()){funcmat_process process = (*iter).v_func_callback;process(nmat);iter++;}}public://以客户端模式启动得输入void func_init(const void* hWnd, const char* url){v_url = url;v_drawer.func_init(hWnd, &v_frames);v_decoder.func_init(url, &v_frames);}void func_push_server_data(uint8_t* data, int len){v_decoder.push(data, len);}//以服务器模式启动得输入void func_init_server(const void* hWnd, const char* url, int codecid,uint8_t* extradata, int extradatalen){v_url = url;v_drawer.func_init(hWnd, &v_frames);v_decoder.func_init(url, &v_frames,codecid, extradata, extradatalen);}void func_start(){v_decoder.Start();}void func_stop(){v_decoder.func_stop();}void func_record_start(const char* filename){v_decoder.func_record_start(filename);}void func_record_close(){v_decoder.func_record_close();}//插入一个串联函数void func_add(func_process process){Lock lock(this);v_funcs.push_back(process);}void func_dec(const char* name){Lock lock(this);auto iter = v_funcs.begin();while (iter != v_funcs.end()){if ((*iter).funcname.compare(name) == 0){v_funcs.erase(iter);break;}iter++;}}//AVFrame* v_cache = NULL;int v_need_cache = 0;AVFrame* func_getrgb(AVFrame** frame){*frame = NULL;std::lock_guard<std::mutex> lock(v_mutex_cache);if (v_cache == NULL)return v_cache;else{*frame = v_cache;v_cache = NULL;}return *frame;}int func_get_decode_width(){return v_decoder.func_get_decode_width();}int func_get_decode_height(){return v_decoder.func_get_decode_height();}//std::list<PlugIn_ptr> v_plugins;std::mutex _plugin_;void plugin_add(std::string name){PlugIn_ptr in = c_plugins::instance()->Get(name);int find = 0;std::lock_guard<std::mutex> lock(_plugin_);auto iter = v_plugins.begin();while (iter != v_plugins.end()){if ((*iter)->name.compare(in->name) == 0){find = 1;break;}iter++;}if (find == 0){v_plugins.push_back(in);}}//从链中删除void plugin_delete(std::string name){std::lock_guard<std::mutex> lock(_plugin_);auto iter = v_plugins.begin();while (iter != v_plugins.end()){//PlugIn* tmp = *iter;if ((*iter)->name.compare(name) == 0){v_plugins.erase(iter);break;}iter++;}}
#ifdef CSTRINGvoid GetPlugInName(vector<CString>& names){USES_CONVERSION;std::lock_guard<std::mutex> lock(_plugin_);auto iter = v_plugins.begin();while (iter != v_plugins.end()){CString str = A2W((*iter)->name.c_str());//CString str = (*iter)->name.c_str();names.emplace_back(str);iter++;}}
#endif/////画一帧图像void func_draw(int px, int py, int drawrect){AVFrame* frame = NULL;if (v_frames.dequeue(&frame)){/*cv::Mat nmat;nmat.cols = frame->width;nmat.rows = frame->height;nmat.data = frame->data[0];*///装载畸形矫正算法//if (!v_funcs.empty())auto iter = v_plugins.begin();while (iter != v_plugins.end()){(*iter)->FUNC_worker(frame->data[0], frame->width, frame->height,NULL);iter++;}v_drawer.func_draw(px, py, frame, drawrect);{和python 脚本进行交互//if (v_script != nullptr && !v_script->IsStop())//{//	if (frame->key_frame)//	{//		int w = frame->width;//		int h = frame->height;//		//数据写入共享内存//		mem_info_ptr ptr = v_script->mem_getch_process(frame->data[0], w, h);//		if (ptr != nullptr)//		{//			v_script->v_in.Push(ptr);//			v_script->Notify();//通知取队列//		}//	}//	if (!v_script->v_out.IsEmpty())//	{//		mem_info_ptr ptr = v_script->v_out.FrontAndPop();//		if (ptr != nullptr)//		{//			//开始画子画面//子画面中开始画结果//			//归还内存//			v_script->mem_return(ptr);//		}//	}//}std::lock_guard<std::mutex> lock(v_mutex_cache);if (v_cache != NULL){av_freep(&v_cache->data[0]);av_frame_free(&v_cache);}//保存最后一帧当前帧v_cache = frame;//是否需要和python脚本进程交互}}}//同时窗口缩小到图片大小,裁剪掉黑边,void func_cut(int windoww, int windowy, int imagew,int imageh){v_drawer.func_cut(windoww, windowy,imagew, imageh);}void func_restore(){v_drawer.func_restore();}//	std::map<string,Script*>script_ptr v_script = nullptr;std::mutex _script_;void func_script_add(std::string path){//_script_.lock();if(v_script==nullptr){v_script = std::make_shared<s_script>();int w = v_decoder.func_get_decode_width();int h = v_decoder.func_get_decode_height();//内存分为5块,每块为w*h*3-->bgr24int blocksize = 5;v_script->func_init(w, h,5,v_url.c_str(),path.c_str());//v_script->add(path);v_script->Start();//processRet("python.exe", path.c_str());}}void func_script_del(std::string path){if (v_script != nullptr)v_script->Stop();}};

三、定义c_script

#include <string>
#include <vector>
#include <algorithm>
#include <future>
#include <chrono>
#include "c_string.h"
#include "tcpclient.h"
#include "memshare.h"
#include "TThreadRunable.h"
typedef struct s_script:public TThreadRunable
{s_script(){}~s_script(){v_container.clear();}//文件路径std::string v_path;std::string v_sharename;std::string v_url;int v_totalblock = 0;int v_w = 0;int v_h = 0;std::list<mem_info_ptr> v_container;//输入flist<mem_info_ptr> v_in;//输出flist<mem_info_ptr> v_out;cmem_map v_map;std::mutex _mr;tcpclient v_tcpclient;mem_info_ptr func_fetch(){std::lock_guard<std::mutex> lock(_mr);if (v_container.size() > 0){mem_info_ptr data = v_container.front();//block = v_container.front().block;v_container.pop_front();return data;}return nullptr;}void func_init(int w, int h,int block,const char* url,const char* path){v_w = w;v_h = h;v_url = url;v_path = path;//有多少个实际内存块v_totalblock = block;}void Stop(){TThreadRunable::Stop();v_tcpclient.Stop();}mem_info_ptr  mem_getch_process(uint8_t* data ,int w, int h){mem_info_ptr mem = nullptr;{std::lock_guard<std::mutex> lock(_mr);if (v_container.size() > 0){mem = v_container.front();//block = v_container.front().block;v_container.pop_front();}else{return nullptr;}}v_map.Write(mem->block, data, w, h);//memcpy(mem->v_mem, data, w*h * 3);return mem;}//从链上归还内存void mem_return(mem_info_ptr ptr){//mem_info_ptr ptr = std::make_shared<s_mem_info>();//ptr->v_mem = data;//ptr->block = block;std::lock_guard<std::mutex> lock(_mr);v_container.emplace_back(ptr);}int func_process(){std::string p = "python.exe ";p += v_path;std::system(p.c_str());return 0;}void Run(){_canstart = false;const char* sharename = getfilename(v_path.c_str());//0 or 1if (v_map.Open(v_w, v_h, v_totalblock , sharename) >= 0){//std::lock_guard<std::mutex> lock(_mr);for (int i = 0; i < v_totalblock; i++){mem_info_ptr meminfo = std::make_shared<s_mem_info>();meminfo->v_mem = v_map.GetBlock(i);meminfo->block = i;v_container.push_back(meminfo);}}int connected = -1;int connectime = 0;while (connected == -1){connected = v_tcpclient.Connect();if (connected == -1){std::this_thread::sleep_for(std::chrono::milliseconds(200));//std::this_thread::sleep_for(std::chrono::mill (1000));}elsebreak;if (++connectime == 10)break;}if (connected && !v_tcpclient.ready())//握手,ready 发送 返回大写 READY{return;}//通知服务端有多少内存if (connected && v_tcpclient.writeInfo(v_w, v_h, v_totalblock,sharename, (int)strlen(sharename)) == -1)return;//auto fut = std::async(std::launch::async,&s_script::func_process,this);while (connected){//注意这里要分配一个端口//发送和接收数据if (IsStop())break;//if (fut.wait_for(5ms) == std::future_status::ready)//	break;this->WaitForSignal();//通知那里有一副图像已经准备好了mem_info_ptr info = v_in.FrontAndPop();if (v_tcpclient.write_signal(info->block) == -1)break;if (v_tcpclient.ready2()){//read 代表处理结束v_out.Push(info);}elsebreak;}v_in.clear();v_out.clear();_stop = true;_canstart = true;v_tcpclient.Stop();}}s_script;

四、定义cmem_map类

和python内存共享

class cmem_map
{HANDLE hFile = NULL;OFSTRUCT opBuf;HANDLE hMapfile = NULL;HANDLE hMapview = NULL;//long offset = 0;
public:cmem_map() {}~cmem_map() {}bool IsOpen(){return (hMapview != NULL);}bool IsClosed(){return (hMapfile == NULL);}int Open(int w,int h,int block, const char* shareName){//hFile = ::CreateFile(memfile_add, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);//if (hFile == 0)//{//	printf("open file failed!\n");//	return -1;//}v_w = w;v_h = h;if (hMapfile != NULL)return 1;//v_mem_block_number = blocknum;//两块内存地址,一块是输入图像内存,一块是输出图像内存int fsize = w * h * 3 * block;//2.为指定文件创建一个有名的文件映象HANDLE hMapfile = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL/*&ScrtyAttr*/, PAGE_READWRITE | SEC_COMMIT, 0, fsize, shareName);//hMapfile = CreateFileMapping((HANDLE)hFile, NULL, PAGE_READWRITE, 0, fsize, L"MapTest");if (hMapfile == NULL){printf("mapping file failed!\n");return -1;}//关闭文件句柄//CloseHandle((HANDLE)hFile);//hFile = 0;hMapview = MapViewOfFile(hMapfile, FILE_MAP_WRITE, 0, 0, 0);if (hMapview == NULL){printf("mapping view failed!\n");return -1;}return 0;}void Close(){UnmapViewOfFile(hMapview);//关闭文件映象句柄CloseHandle(hMapfile);hMapfile = 0;}int Write(int block, uint8_t* data, int w,int h){uint8_t* recv = (uint8_t*)hMapview;recv += block*w*h*3;memcpy(recv, data, w*h*3);//把文件映射视图中的修改的内容或全部写回到磁盘文件中FlushViewOfFile(recv,w*h*3);return 0;}//int v_mem_block_number = 0;int v_w = 0;int v_h = 0;//int v_now_mem_point = -1;//uint8_t* v_read = NULL;//uint8_t* v_write = NULL;//uint8_t* GetFirst()//{//	v_now_mem_point=0;//	uint8_t *recv = (uint8_t *)hMapview;//	return recv;//}uint8_t* GetBlock(int block){//v_now_mem_point++;//if (v_now_mem_point == v_mem_block_number)//	v_now_mem_point = 0;uint8_t *recv = (uint8_t *)hMapview;recv += v_w * v_h * 3 * block;return recv;}
};typedef struct s_mem_info
{uint8_t* v_mem = NULL;int block = 0;
}s_mem_info;
typedef std::shared_ptr<s_mem_info> mem_info_ptr;

五、负责和python通信

使用socket进行通信

#define ASIO_STANDALONE
#include "asio.hpp"
#include "asio/buffer.hpp"
#include "asio/io_context.hpp"
#include "asio/ip/tcp.hpp"
#include "asio/read_until.hpp"
#include "asio/steady_timer.hpp"
#include "asio/write.hpp"
#include <functional>
#include <iostream>
#include <string>using asio::steady_timer;
using asio::ip::tcp;
using std::placeholders::_1;
using std::placeholders::_2;
class tcpclient
{asio::io_context ioc;asio::ip::tcp::resolver resolver;// (ioc);asio::ip::tcp::socket socket;// (ioc);
public:tcpclient():resolver(ioc),socket(ioc){}~tcpclient(){Stop();}
public:int Connect(){try{asio::ip::tcp::endpoint ep(asio::ip::address::from_string("127.0.0.1"), 11000);socket.connect(ep);if (!socket.is_open()){//AfxMessageBox(L"连接服务器失败");//std::cout << "连接服务器失败" << std::endl;return -1;}return 1;}catch (std::exception& e){std::cerr << "Exception: " << e.what() << "\n";return -1;}}void Stop(){if (socket.is_open())socket.close();}//第一次握手,ready READY接收bool ready(){try{asio::write(socket, asio::buffer("ready", 5));char buffer[6];int len = 5;size_t rl = asio::read(socket, asio::buffer(buffer,len));buffer[5] = '\0';const char* src = &buffer[0];const char* dst = "READY";if (strcmp(src, dst) == 0){return true;}return false;}catch (std::exception& e){std::cerr << "Exception: " << e.what() << "\n";return false;}}//第二次握手协议,接收到ready 后发送blockbool ready2(){try{char buffer[6];int len = 5;size_t rl = asio::read(socket, asio::buffer(buffer, len));buffer[5] = '\0';const char* src = &buffer[0];const char* dst = "ready";if (strcmp(src, dst) == 0){return true;}return false;}catch (std::exception& e){std::cerr << "Exception: " << e.what() << "\n";return false;}}//第二次发送基本信息,图像的分辨率 block内存块数, 发送的内存共享地址名称size_t writeInfo(uint16_t width,uint16_t height,uint16_t block,const char* data, int len){try{char buffer[256];int totallen = 2 * 3 + len;if (totallen + 4 > 256)return -1;char* pos = &buffer[0];char* head = pos;uint32_t* tmp = (uint32_t*)pos;*tmp = totallen;pos += 4;memcpy(pos, &width, 2);pos += 2;memcpy(pos, &height, 2);pos += 2;memcpy(pos, &block, 2);pos += 2;memcpy(pos, data, len);//10 is 4+2+2+2return asio::write(socket, asio::buffer(head, 10 + len));}catch (std::exception& e){std::cerr << "Exception: " << e.what() << "\n";return -1;}}//写入两个字节的信号,block为内存的哪一块size_t write_signal(uint16_t block){try{uint8_t* pos = (uint8_t*)&block;return asio::write(socket, asio::buffer(pos, 2));}catch (std::exception& e){std::cerr << "Exception: " << e.what() << "\n";return -1;}}
};

六、python 共享内存

import socket  	
import threading
import cv2
import numpy as np
#from PIL import Image
from mmap import mmap
import contextlib
import time
import mtcnn
print(mtcnn.__version__)def recvsize(clientsock,addr,num):had_received = 0data_body = bytes()while had_received<num:part = clientsock.recv(num)data_body +=partpart_len = len(part)had_received += part_lenreturn data_body
def recv(clientsock,addr,detector):#data = clientsock.recv(4)clientsock.send("ready")data = recvsize(clientsock,addr,4)# 得到协议四字节长度totalsize =  (data[3]<<24)+ (data[2]<<16)+(data[1]<< 8)+data[0]data = recvsize(clientsock,addr,2)width = (data[1]<<8)+ data[0]data  = recvsize(clientsock,addr,2)height = (data[1]<<8)+ data[0]data = recvsize(clientsock,addr,2)blocktotal = (data[1]<<8)+ data[0]name = recvsize(clientsock,addr,totalsize-6)   memsize = width*height*3*blocktotal*2with contextlib.closing(mmap.mmap(-1, memsize, tagname=name, access=mmap.ACCESS_WRITE)) as m:while True:data = recvsize(clientsock,addr,2)block = (data[1]<<8)+ data[0]m.seek(width*height*3*2* block)data_body = m.read(width*height*3)#bgr  frombuf = np.frombuffer(data_body, np.uint8)img = np.array(frombuf).reshape((height, width, 3)).astype(np.uint8)faces = detector.detect_faces(pixels)for result in faces:x,y,width,height = result['box']leye = result['keypoints']['left_eye']cv2.rectangle(pixels,(x,y),(x+width,y+height),(0, 255, 0),2)clientsock.send("ready")#cv2.imshow("test",img)def main():#with contextlib.closing(mmap.mmap(-1, 1024, tagname='test', access=mmap.ACCESS_WRITE)) as m:#准备人脸识别detector = MTCNN()host = '127.0.0.1' #主机IP			port = 11000		  #端口web = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#创建TCP/IP套接字web.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)web.bind((host, port))					#绑定端口web.listen(5)							#设置最多连接数print("服务器等待客户端连接...")		while True:conn, addr = web.accept()   		#建立客户端连接print("addr is",addr)t1 = threading.Thread(target=recv,args=(conn,addr,detector))#创建一个死循环
if __name__ == '__main__':main()
http://www.lryc.cn/news/580361.html

相关文章:

  • 后端树形结构
  • STM32F103RCTx的PWM输出控制电机
  • js游戏简单修改
  • React Native 开发环境搭建--mac--android--奔溃的一天
  • Hinge×亚矩云手机:以“深度连接”为名,重构云端社交的“真实感”
  • CSS02:四种CSS导入方式
  • pyspark大规模数据加解密优化实践
  • Python小工具之PDF合并
  • 数据结构:多维数组在内存中的映射(Address Mapping of Multi-dimensional Arrays)
  • IDEA中application.yml配置文件不自动提示解决办法
  • 如何在IntelliJ IDEA中设置数据库连接全局共享
  • 从“电话催维修“到“手机看进度“——售后服务系统开发如何重构客户体验
  • CppCon 2018 学习:Surprises In Object Lifetime
  • Kotlin 协程:Channel 与 Flow 深度对比及 Channel 使用指南
  • 【ES6】Latex总结笔记生成器(网页版)
  • Jenkins Pipeline(二)
  • 【Elasticsearch】深度分页及其替代方案
  • 【openp2p】 学习2:源码阅读P2PNetwork和P2PTunnel
  • 【STM32实践篇】:GPIO 详解
  • 网络资源模板--基于Android Studio 实现的极简天气App
  • Excel 数据透视表不够用时,如何处理来自多个数据源的数据?
  • 动手实践OpenHands系列学习笔记1:Docker基础与OpenHands容器结构
  • Softhub软件下载站实战开发(十三):软件管理前端分片上传实现
  • 用户中心Vue3网页开发(1.0版)
  • Java零基础笔记01(JKD及开发工具IDEA安装配置)
  • Linux进程管理:从基础到实战
  • 60天python训练计划----day59
  • 数据结构:数组:插入操作(Insert)与删除操作(Delete)
  • 深度学习4(浅层神经网络)
  • 【深度学习】神经网络剪枝方法的分类