소스 검색

add h264transjpeg_civetweb.

yuchuli 3 년 전
부모
커밋
74168b6b97

+ 219 - 4
src/driver/driver_h264_dec/ivh264framedecode.cpp

@@ -1,6 +1,8 @@
 #include "ivh264framedecode.h"
 
+#include <iostream>
 
+#ifdef USE_QSV
 static void yuvNV12ToI420(char *NV12,int w,int h,char *I420)
 {
     memcpy(I420,NV12,w*h);//y分量
@@ -10,17 +12,23 @@ static void yuvNV12ToI420(char *NV12,int w,int h,char *I420)
          memcpy(I420+w*h+w*h/4+i,NV12+w*h+j+1,1);//v分量
     }
 }
+#endif
 
-
-ivh264framedecode::ivh264framedecode(int framewidth,int frameheight)
+ivh264framedecode::ivh264framedecode(int framewidth,int frameheight,bool bJpegEnc)
 {
+    mbTransJpeg = bJpegEnc;
     mframeheight = frameheight;
     mframewidth = framewidth;
+    mjpegdata.mbupdate = false;
 
     int i;
     for(i=0;i<FRAMEDECBUFSIZE;i++)
     {
+#ifndef USEJPEG_NOOPENCV
         mdecbuf[i].mbuf.myuvImg.create(mframeheight*3/2, mframewidth, CV_8UC1);
+#else
+        mdecbuf[i].mbuf.mpyuv_ptr = std::shared_ptr<char>(new char[mframeheight* mframewidth*3/2]);
+#endif
         mdecbuf[i].mbuf.framewidth = mframewidth;
         mdecbuf[i].mbuf.frameheight = mframeheight;
 
@@ -109,6 +117,118 @@ void ivh264framedecode::UnlockWriteBuff(int nbufindex)
     mmutexstate.unlock();
 }
 
+
+int ivh264framedecode::GetJpegData(std::shared_ptr<char> & pstr_ptr,int & ndatasize,int nwaitms)
+{
+    if(mjpegdata.mbupdate)
+    {
+        mjpegdata.mmutexdata.lock();
+        pstr_ptr = mjpegdata.mpstr_ptr;
+        ndatasize = mjpegdata.ndatasize;
+        mjpegdata.mbupdate = false;
+        mjpegdata.mmutexdata.unlock();
+        return 1;
+    }
+
+    if(nwaitms<=0)return 0;
+
+    std::unique_lock<std::mutex> lk(mmutex_cvjpeg);
+    if(mcvjpeg.wait_for(lk, std::chrono::milliseconds(nwaitms)) == std::cv_status::timeout)
+    {
+        lk.unlock();
+        return 0;
+    }
+    else
+    {
+        lk.unlock();
+    }
+
+    if(mjpegdata.mbupdate)
+    {
+        mjpegdata.mmutexdata.lock();
+        pstr_ptr = mjpegdata.mpstr_ptr;
+        ndatasize = mjpegdata.ndatasize;
+        mjpegdata.mmutexdata.unlock();
+        return 1;
+    }
+    return 0;
+
+}
+
+void ivh264framedecode::encodejpeg(AVFrame *frame)
+{
+    static int nindex = 0;
+    int nsample = 3;
+
+    if(nindex>nsample)
+    {
+        nindex = 0;
+    }
+    nindex++;
+    if(nindex != 1)
+    {
+        return;
+    }
+
+
+    av_opt_set(mpCodecCtxJpeg->priv_data, "qscale:v", "95", 0);
+#define DEBUG_ENCODEJPEG
+    int ret;
+    AVCodecContext * enc_ctx = mpCodecCtxJpeg;
+    AVPacket pkt;
+    int y_size = enc_ctx->width * enc_ctx->height;
+
+#ifdef DEBUG_ENCODEJPEG
+    int64_t time1 = std::chrono::system_clock::now().time_since_epoch().count()/1000;
+#endif
+
+    av_new_packet(&pkt, y_size*2);  //给AVPacket申请空间
+
+
+    ret = avcodec_send_frame(enc_ctx, frame);
+    if (ret < 0) {
+        fprintf(stderr, "Error sending a frame for jpeg encoding\n");
+        av_packet_unref(&pkt);
+        return;
+    }
+
+    while (ret >= 0) {
+        ret = avcodec_receive_packet(enc_ctx, &pkt);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+        {
+            av_packet_unref(&pkt);
+            return;
+        }
+        else if (ret < 0) {
+            fprintf(stderr, "Error during encoding\n");
+            av_packet_unref(&pkt);
+            return;
+        }
+
+        std::shared_ptr<char> pstr_data = std::shared_ptr<char>(new char[pkt.size]);
+        memcpy(pstr_data.get(),pkt.data,pkt.size);
+        mjpegdata.mmutexdata.lock();
+        mjpegdata.mpstr_ptr = pstr_data;
+        mjpegdata.ndatasize = pkt.size;
+        mjpegdata.mnupdatetime = std::chrono::system_clock::now().time_since_epoch().count();
+        mjpegdata.mbupdate = true;
+        mjpegdata.mmutexdata.unlock();
+        mcvjpeg.notify_all();
+
+#ifdef DEBUG_ENCODEJPEG
+        int64_t time2 = std::chrono::system_clock::now().time_since_epoch().count()/1000;
+        double codetime = time2-time1;
+        codetime = codetime/1000.0;
+        std::cout<<" pictrue size: "<<pkt.size<<" code time: "<<codetime<< std::endl;
+#endif
+//        fwrite(pkt->data, 1, pkt->size, outfile);
+        av_packet_unref(&pkt);
+    }
+
+
+
+}
+
 void ivh264framedecode::decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt)
 {
 //    char buf[1024];
@@ -138,13 +258,20 @@ void ivh264framedecode::decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket
 //        snprintf(buf, sizeof(buf), "%s-%d", filename, dec_ctx->frame_number);
 
 
+        if(mbTransJpeg)
+        {
+ //           encodejpeg(frame);
+        }
 //        cv::Mat yuvImg;
 //        cv::Mat rgbImg(cy, cx,CV_8UC3);
 
         int index = GetEmptyIndex();
         if(index < 0)
         {
-            std::cout<<" no empty buffer used. "<<std::endl;
+#ifndef USEJPEG_NOOPENCV
+//            std::cout<<" no empty buffer used. "<<std::endl;
+#endif
+ //           index = 0;
             break;
         }
         iv::framedecodebuf * pbuf = LockWriteBuff(index);
@@ -153,7 +280,11 @@ void ivh264framedecode::decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket
         {
             mframeheight = frame->height;
             mframewidth = frame->width;
+#ifndef USEJPEG_NOOPENCV
             pbuf->myuvImg.create(mframeheight*3/2, mframewidth, CV_8UC1);
+#else
+            pbuf->mpyuv_ptr = std::shared_ptr<char>(new char[mframeheight*mframewidth*3/2]);
+#endif
             pbuf->frameheight = mframeheight;
             pbuf->framewidth = mframewidth;
             std::cout<<"change width to : "<<mframewidth<<" change heigth to: "<<mframeheight<<std::endl;
@@ -172,13 +303,47 @@ void ivh264framedecode::decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket
 #endif
 
 #ifndef USE_QSV
+#ifndef USEJPEG_NOOPENCV
         memcpy(pbuf->myuvImg.data, frame->data[0], cy*cx);
         memcpy(pbuf->myuvImg.data + cy*cx,frame->data[1],cy*cx/4);
         memcpy(pbuf->myuvImg.data + cy*cx + cy*cx/4,frame->data[2],cy*cx/4);
+#else
+        char * pstrdata = pbuf->mpyuv_ptr.get();
+        memcpy(pstrdata,frame->data[0],cy*cx);
+        memcpy(pstrdata +cy*cx,frame->data[1],cy*cx/4);
+        memcpy(pstrdata +cy*cx+cy*cx/4,frame->data[2],cy*cx/4);
 #endif
+#endif
+
+        if(mbTransJpeg)
+        {
+            std::vector<int> param = std::vector<int>(2);
+            param[0] = CV_IMWRITE_JPEG_QUALITY;
+            param[1] = 95; // default(95) 0-100
+            std::vector<unsigned char> buff;
+
+            cv::Mat mat1;
+
+            cv::cvtColor(pbuf->myuvImg,mat1,cv::COLOR_YUV2BGR_I420);
+            cv::imencode(".jpg", mat1, buff, param);
+
+            std::shared_ptr<char> pstr_data = std::shared_ptr<char>(new char[buff.size()]);
+            memcpy(pstr_data.get(),buff.data(),buff.size());
+            mjpegdata.mmutexdata.lock();
+            mjpegdata.mpstr_ptr = pstr_data;
+            mjpegdata.ndatasize =buff.size();
+            mjpegdata.mnupdatetime = std::chrono::system_clock::now().time_since_epoch().count();
+            mjpegdata.mbupdate = true;
+            mjpegdata.mmutexdata.unlock();
+            mcvjpeg.notify_all();
+
+            buff.clear();
+        }
         UnlockWriteBuff(index);
         mcvread.notify_all();
 
+
+
 //        yuvImg.create(cy*3/2, cx, CV_8UC1);
 //        memcpy(yuvImg.data, frame->data[0], cy*cx);
 //        memcpy(yuvImg.data + cy*cx,frame->data[1],cy*cx/4);
@@ -198,7 +363,7 @@ void ivh264framedecode::threaddecode()
     AVCodecContext *c= NULL;
     AVFrame *frame;
     uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
-    int ret;
+//    int ret;
     AVPacket *pkt;
 
 #ifndef USE_QSV
@@ -261,6 +426,50 @@ void ivh264framedecode::threaddecode()
         exit(1);
     }
 
+
+//    AVFormatContext* pFormatCtx;
+//    AVStream* pStream;
+    AVCodec* pCodec;
+    if(mbTransJpeg)
+    {
+ //       pFormatCtx = avformat_alloc_context();   //分配AVFormatCtx
+//        pStream = avformat_new_stream(pFormatCtx, 0);
+//        if (NULL == pStream)
+//        {
+//            std::cout<<" JPEG Create pStream fail."<<std::endl;
+//            return;
+//        }
+
+
+        pCodec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); //查找编码器
+        if (NULL == pCodec)
+        {
+            printf("can not find  jpeg codec!\n");
+            return;
+        }
+
+        /*设置相关信息*/
+        mpCodecCtxJpeg = avcodec_alloc_context3(pCodec);
+//        mpCodecCtxJpeg = pStream->codec;
+        mpCodecCtxJpeg->codec_id = AV_CODEC_ID_MJPEG;
+        mpCodecCtxJpeg->codec_type = AVMEDIA_TYPE_VIDEO;
+        mpCodecCtxJpeg->pix_fmt = AV_PIX_FMT_YUVJ420P;
+        mpCodecCtxJpeg->width = mframewidth;
+        mpCodecCtxJpeg->height = mframeheight;
+        mpCodecCtxJpeg->time_base.num = 1;
+        mpCodecCtxJpeg->time_base.den = 25;
+
+
+        av_opt_set_int(mpCodecCtxJpeg->priv_data, "qscale",1, 0);
+
+        if (avcodec_open2(mpCodecCtxJpeg, pCodec, NULL) < 0)
+        {
+            printf("con not open jpeg codec!\n");
+            return;
+        }
+    }
+
+
 //    char * strbuff = new char[10000000];
 //    int ndatasize = 0;
     while (mbthreadrun) {
@@ -292,6 +501,8 @@ void ivh264framedecode::threaddecode()
         {
  //           std::cout<<"decode ."<<std::endl;
             decode(c, frame, pkt);
+
+
         }
 
     }
@@ -300,6 +511,9 @@ void ivh264framedecode::threaddecode()
 //    decode(c, frame, NULL, outfilename);
 
 
+    avcodec_free_context(&mpCodecCtxJpeg);
+//    avcodec_close(pStream->codec);
+//    avformat_free_context(pFormatCtx);
 
     av_parser_close(parser);
     avcodec_free_context(&c);
@@ -311,6 +525,7 @@ void ivh264framedecode::threaddecode()
 
 void ivh264framedecode::addframedata(iv::rawframedata & xraw)
 {
+    if(mvectorrawframe.size()>10000)return;
     mmutexframe.lock();
     mvectorrawframe.push_back(xraw);
     mmutexframe.unlock();

+ 31 - 1
src/driver/driver_h264_dec/ivh264framedecode.h

@@ -14,6 +14,7 @@ extern "C"
 
 }
 
+#ifndef USEJPEG_NOOPENCV
 #include <opencv2/opencv.hpp>
 #include <opencv2/core.hpp>
 
@@ -21,6 +22,7 @@ extern "C"
 
 //#include "opencv2/imgcodecs/legacy/constants_c.h"
 #include <opencv2/imgproc/types_c.h>
+#endif
 
 #include <memory>
 #include <vector>
@@ -35,7 +37,11 @@ namespace iv {
     {
         std::shared_ptr<char> mpstr_ptr;
         char * data[3];
+#ifndef USEJPEG_NOOPENCV
         cv::Mat myuvImg;
+#else
+        std::shared_ptr<char> mpyuv_ptr;
+#endif
         int mrealdatasize;
         int framewidth;
         int frameheight;
@@ -52,13 +58,22 @@ namespace iv {
         int ndatasize;
     };
 
+    struct jpegdata
+    {
+        std::shared_ptr<char> mpstr_ptr;
+        int ndatasize;
+        bool mbupdate;
+        int64_t mnupdatetime;  //nano seconds
+        std::mutex mmutexdata;
+    };
+
 }
 
 
 class ivh264framedecode
 {
 public:
-    ivh264framedecode(int framewidth,int frameheight);
+    ivh264framedecode(int framewidth,int frameheight,bool bJpegEnc = false);
 
 public:
     //Return which buffer update.
@@ -77,6 +92,7 @@ private:
 
 private:
     void decode(AVCodecContext *dec_ctx, AVFrame *frame, AVPacket *pkt);
+    void encodejpeg(AVFrame * frame);
     void threaddecode();
 
 private:
@@ -100,6 +116,20 @@ private:
     std::condition_variable mcvread;
 
 
+private:
+    bool mbTransJpeg = true;
+
+    AVCodecContext * mpCodecCtxJpeg = NULL;
+    iv::jpegdata mjpegdata;
+
+    std::mutex mmutex_cvjpeg;
+    std::condition_variable mcvjpeg;
+
+public:
+    //if GetData return 1, else return 0
+    int GetJpegData(std::shared_ptr<char> & pstr_ptr,int & ndatasize, int nwaitms = 0);
+
+
 
 
 

+ 64 - 0
src/tool/h264transjpeg_civetweb/h264transjpeg_civetweb.pro

@@ -0,0 +1,64 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2022-05-06T13:38:05
+#
+#-------------------------------------------------
+
+QT       += core gui
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = h264transjpeg_civetweb
+TEMPLATE = app
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which has been marked as deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
+
+
+SOURCES += \
+        ../../../thirdpartylib/civetweb/CivetServer.cpp \
+        ../../../thirdpartylib/civetweb/civetweb.c \
+        main.cpp \
+        mainwindow.cpp  \
+    ../../driver/driver_h264_dec/ivh264framedecode.cpp \
+    transjpegweb.cpp \
+    ../RemoteCtrl_h264/rtspclientdown.cpp
+
+HEADERS += \
+    ../../../thirdpartylib/civetweb/CivetServer.h \
+    ../../../thirdpartylib/civetweb/civetweb.h \
+        mainwindow.h  \
+    ../../driver/driver_h264_dec/ivh264framedecode.h \
+    transjpegweb.h \
+    ../RemoteCtrl_h264/rtspclientdown.h
+
+
+FORMS += \
+        mainwindow.ui
+
+INCLUDEPATH += $$PWD/../../../thirdpartylib/civetweb
+
+DEFINES += NO_SSL
+#DEFINES += NO_SSL_DL
+DEFINES += USE_WEBSOCKET
+
+INCLUDEPATH += $$PWD/../../driver/driver_h264_dec
+INCLUDEPATH += $$PWD/../RemoteCtrl_h264
+
+LIBS += -ldl -lrt
+
+INCLUDEPATH += /usr/include/x86_64-linux-gnu
+LIBS +=  -lavcodec -lavformat -lavutil
+
+
+#DEFINES += USEJPEG_NOOPENCV
+LIBS += -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_imgcodecs -lopencv_video  -lopencv_videoio -lpthread #-lopencv_shape
+

+ 11 - 0
src/tool/h264transjpeg_civetweb/main.cpp

@@ -0,0 +1,11 @@
+#include "mainwindow.h"
+#include <QApplication>
+
+int main(int argc, char *argv[])
+{
+    QApplication a(argc, argv);
+    MainWindow w;
+    w.show();
+
+    return a.exec();
+}

+ 15 - 0
src/tool/h264transjpeg_civetweb/mainwindow.cpp

@@ -0,0 +1,15 @@
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+MainWindow::MainWindow(QWidget *parent) :
+    QMainWindow(parent),
+    ui(new Ui::MainWindow)
+{
+    ui->setupUi(this);
+    mptjw = new transjpegweb();
+}
+
+MainWindow::~MainWindow()
+{
+    delete ui;
+}

+ 26 - 0
src/tool/h264transjpeg_civetweb/mainwindow.h

@@ -0,0 +1,26 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+#include "transjpegweb.h"
+
+namespace Ui {
+class MainWindow;
+}
+
+class MainWindow : public QMainWindow
+{
+    Q_OBJECT
+
+public:
+    explicit MainWindow(QWidget *parent = 0);
+    ~MainWindow();
+
+private:
+    Ui::MainWindow *ui;
+
+    transjpegweb * mptjw;
+};
+
+#endif // MAINWINDOW_H

+ 24 - 0
src/tool/h264transjpeg_civetweb/mainwindow.ui

@@ -0,0 +1,24 @@
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>MainWindow</string>
+  </property>
+  <widget class="QMenuBar" name="menuBar" />
+  <widget class="QToolBar" name="mainToolBar" />
+  <widget class="QWidget" name="centralWidget" />
+  <widget class="QStatusBar" name="statusBar" />
+ </widget>
+ <layoutDefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections/>
+</ui>

+ 97 - 0
src/tool/h264transjpeg_civetweb/transjpegweb.cpp

@@ -0,0 +1,97 @@
+#include "transjpegweb.h"
+
+#include <iostream>
+
+#define DOCUMENT_ROOT "./frontend"
+
+
+
+transjpegweb::transjpegweb()
+{
+    mg_init_library(0);
+
+
+    const char *options[] = {
+        "document_root", DOCUMENT_ROOT, "listening_ports", "6123", 0};
+
+    std::vector<std::string> cpp_options;
+    for (int i=0; i<(sizeof(options)/sizeof(options[0])-1); i++) {
+        cpp_options.push_back(options[i]);
+    }
+
+    // CivetServer server(options); // <-- C style start
+    mpserver = new CivetServer(cpp_options); // <-- C++ style start
+
+    std::string strfront = "rtsp://"+mstrrtspserverip+":"+mstrrtspserverport+"/"+mstrvin+"-front-"+mstrrtsppass;
+    mprtspdown[0] = new rtspclientdown(strfront);
+    std::string strrear = "rtsp://"+mstrrtspserverip+":"+mstrrtspserverport+"/"+mstrvin+"-rear-"+mstrrtsppass;
+    mprtspdown[1] = new rtspclientdown(strrear);
+    std::string strleft = "rtsp://"+mstrrtspserverip+":"+mstrrtspserverport+"/"+mstrvin+"-left-"+mstrrtsppass;
+    mprtspdown[2] = new rtspclientdown(strleft);
+    std::string strright = "rtsp://"+mstrrtspserverip+":"+mstrrtspserverport+"/"+mstrvin+"-right-"+mstrrtsppass;
+    mprtspdown[3] = new rtspclientdown(strright);
+
+    int i;
+    for(i=0;i<NUM_CAM;i++)
+    {
+        mpws[i] = new WebSocketHandler();
+        mph264decode[i] = new ivh264framedecode(mnframewidth,mnframeheight,true);
+        mpthreadframe[i] = new std::thread(&transjpegweb::threadframe,this,i);
+        mpthreadpic[i] = new std::thread(&transjpegweb::threadpic,this,i);
+    }
+
+    mpserver->addWebSocketHandler("/front",mpws[0]);
+    mpserver->addWebSocketHandler("/rear",mpws[1]);
+    mpserver->addWebSocketHandler("/left",mpws[2]);
+    mpserver->addWebSocketHandler("right",mpws[3]);
+}
+
+
+void transjpegweb::threadframe(int ncam)
+{
+    while(mbthreadrun)
+    {
+        iv::h264rawframedata xframe;
+        if(mprtspdown[ncam]->Getrtspframe(xframe,30) == 1)
+        {
+            iv::rawframedata xraw;
+            xraw.mpstr_ptr = xframe.mpstr_ptr;
+            xraw.ndatasize = xframe.mdatasize;
+            mph264decode[ncam]->addframedata(xraw);
+        }
+    }
+}
+
+#include <QFile>
+void transjpegweb::threadpic(int ncam)
+{
+
+    int nsave = 0;
+    int nsample = 1;
+    int nnow = 1;
+    while(mbthreadrun)
+    {
+        std::shared_ptr<char> pstr_ptr;
+        int ndatasize;
+        if(mph264decode[ncam]->GetJpegData(pstr_ptr,ndatasize,30) == 1)
+        {
+            if(nnow == 1)
+                mpws[ncam]->BroadData(pstr_ptr.get(),ndatasize);
+            nnow++;
+            if(nnow>nsample)nnow = 1;
+//            std::cout<<" get jpg . size: "<<ndatasize<<std::endl;
+            if(nsave <35)
+            {
+                QFile xFile;
+                std::string strpath = "/home/yuchuli/testjpg/"+QString::number(ncam).toStdString()+"-"+ QString::number(nsave).toStdString()+ ".jpg";
+                xFile.setFileName(strpath.data());
+                if(xFile.open(QIODevice::ReadWrite))
+                {
+                    xFile.write(pstr_ptr.get(),ndatasize);
+                    xFile.close();
+                }
+                nsave++;
+            }
+        }
+    }
+}

+ 118 - 0
src/tool/h264transjpeg_civetweb/transjpegweb.h

@@ -0,0 +1,118 @@
+#ifndef TRANSJPEGWEB_H
+#define TRANSJPEGWEB_H
+
+#include "CivetServer.h"
+#include <cstring>
+
+#include <mutex>
+#include <iostream>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "rtspclientdown.h"
+#include "ivh264framedecode.h"
+
+#define NUM_CAM 4
+
+
+#ifdef USE_WEBSOCKET
+class WebSocketHandler : public CivetWebSocketHandler {
+
+
+    std::vector<struct mg_connection *> mvectorconn;
+    std::mutex mMutex;
+public:
+    void BroadData(const char * strdata,int ndata)
+    {
+        int i;
+        mMutex.lock();
+        for(i=0;i<(int)mvectorconn.size();i++)
+        {
+            std::cout<<" send frame data . size : "<<ndata<<std::endl;
+            mg_websocket_write(mvectorconn[i], MG_WEBSOCKET_OPCODE_BINARY, strdata, ndata);
+        }
+        mMutex.unlock();
+    }
+    int a = 1;
+private:
+    virtual bool handleConnection(CivetServer *server,
+                                  const struct mg_connection *conn) {
+        printf("WS connected\n");
+        return true;
+    }
+
+    virtual void handleReadyState(CivetServer *server,
+                                  struct mg_connection *conn) {
+        printf("WS ready\n");
+
+        mMutex.lock();
+        mvectorconn.push_back(conn);
+        mMutex.unlock();
+    }
+
+    virtual bool handleData(CivetServer *server,
+                            struct mg_connection *conn,
+                            int bits,
+                            char *data,
+                            size_t data_len) {
+
+        return true;
+//        return (data_len<5);
+    }
+
+    virtual void handleClose(CivetServer *server,
+                             const struct mg_connection *conn) {
+        printf("WS closed\n");
+        int i;
+        mMutex.lock();
+        for(i=0;i<(int)mvectorconn.size();i++)
+        {
+            if(conn == mvectorconn[i])
+            {
+                mvectorconn.erase(mvectorconn.begin()+i);
+                break;
+            }
+        }
+        mMutex.unlock();
+    }
+};
+#endif
+
+
+class transjpegweb
+{
+public:
+    transjpegweb();
+
+private:
+    CivetServer * mpserver;
+
+
+    std::string mstrrtspserverport = "9554";
+    std::string mstrrtspserverip = "111.33.136.149";
+    std::string mstrvin = "AAAAAAAAAAAAAAAAA";
+    std::string mstrrtsppass = "hello";
+
+    rtspclientdown * mprtspdown[4];
+    ivh264framedecode * mph264decode[NUM_CAM];
+
+    std::thread * mpthreadframe[NUM_CAM];
+    std::thread * mpthreadpic[NUM_CAM];
+
+    int mnframewidth = 1920;
+    int mnframeheight = 1080;
+
+    void threadframe(int ncam);
+    void threadpic(int ncam);
+
+    bool mbthreadrun = true;
+
+    WebSocketHandler * mpws[NUM_CAM];
+
+};
+
+#endif // TRANSJPEGWEB_H