Ticket #521: qthcamera.cpp

File qthcamera.cpp, 17.9 KB (added by mrdebug, 5 years ago)
Line 
1#include "qthcamera.h"
2
3QThCamera::QThCamera(QObject *parent) : QThread(parent) {
4    MainForm= (QFMainForm*)parent;
5    DoStart= true;
6}
7
8QThCamera::~QThCamera() {
9    DoStart= false;
10    while (this->isRunning()) msleep(10);
11    qDebug() << "QThCamera::~QThCamera()";
12}
13
14void QThCamera::IplImageToAVFrame(IplImage* iplImage, AVFrame* avFrame, int Width, int Height, enum PixelFormat pix_fmt) {
15    int linesize[4]= {0, 0, 0, 0};
16    struct SwsContext* img_convert_ctx= sws_getContext(iplImage->width, iplImage->height, PIX_FMT_BGR24, Width, Height, pix_fmt, SWS_BICUBIC, 0, 0, 0);
17    if (img_convert_ctx!= 0) {
18        linesize[0]= 3 * iplImage->width;
19        sws_scale(img_convert_ctx, (uint8_t**)&iplImage->imageData, linesize, 0, iplImage->height, avFrame->data, avFrame->linesize);
20        sws_freeContext(img_convert_ctx);
21    }
22}
23
24typedef struct DynBuffer {
25    int pos, size, allocated_size;
26    uint8_t *buffer;
27    int io_buffer_size;
28    uint8_t io_buffer[1];
29} DynBuffer;
30
31void QThCamera::run() {
32    qDebug() << "QThCamera::run() start";
33    QString MPGFileName= "a.mp4";
34
35    CvCapture *Capture= NULL;
36    Capture= cvCreateCameraCapture(Index, Width, Height);
37    if (!Capture) qDebug() << "cvCreateCameraCapture Error!";
38    else {
39        if (ExternalFrame) cvNamedWindow("Frame", CV_WINDOW_AUTOSIZE);
40        IplImage *frame= 0;
41        CvFont font;
42        cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5f, 0.5f);
43
44        AVOutputFormat *pOutputFormat= av_guess_format("mp4", NULL, NULL); // CODEC_ID_H264 -> mp4, rawvideo; CODEC_ID_THEORA -> ogg; CODEC_ID_MPEG4 -> mpegts, rawvideo; CODEC_ID_VP8 -> webm
45        if (!pOutputFormat) {
46            qDebug() << "Could not set output format, using MPEG.";
47            pOutputFormat= av_guess_format("mpeg", NULL, NULL);
48        }
49        if (!pOutputFormat) qDebug() << "av_guess_format Error!";
50        else {
51            AVFormatContext *pFormatCtx;
52            if (avformat_alloc_output_context2(&pFormatCtx, pOutputFormat, NULL, NULL)< 0) qDebug() << "avformat_alloc_output_context2 Error!";
53            else {
54                AVStream *pVideoStream= av_new_stream(pFormatCtx, 0);
55                if (!pVideoStream) qDebug() << "av_new_stream Error!";
56                else {
57                    AVCodecContext *pCodecCtx= pVideoStream->codec;
58                    pCodecCtx->codec_id= CODEC_ID_H264;
59                    pCodecCtx->codec_type= AVMEDIA_TYPE_VIDEO;
60                    pCodecCtx->bit_rate= 40000;
61                    pCodecCtx->width= Width;
62                    pCodecCtx->height= Height;
63                    pCodecCtx->time_base.den= 25;
64                    pCodecCtx->time_base.num= 1;
65                    pCodecCtx->gop_size= 10;
66                    pCodecCtx->pix_fmt= PIX_FMT_YUV420P;
67                    if (pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER) pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
68                    av_dump_format(pFormatCtx, 0, NULL, 1);
69                    AVCodec *pCodec= avcodec_find_encoder(pCodecCtx->codec_id);
70                    if (!pCodec) qDebug() << "avcodec_find_encoder Error!";
71                    else {
72                        if (avcodec_open(pCodecCtx, pCodec)< 0) qDebug() << "avcodec_open Error!";
73                        else {
74                            QFile QFMPGFileOut;
75                            QFMPGFileOut.setFileName(MPGFileName);
76                            if (QFMPGFileOut.open(QIODevice::WriteOnly)) {
77
78                                if (avio_open_dyn_buf(&pFormatCtx->pb)< 0) qDebug() << "avio_open Error!";
79                                else {
80                                    if (avformat_write_header(pFormatCtx, NULL)!= 0) qDebug() << "av_write_header Error!";
81                                    int BYTEPIC= Width * Height * 3;
82                                    uint8_t *pOutBuffer= (uint8_t*)malloc(BYTEPIC); {
83                                        int Frames= 0;
84                                        QDateTime QDTStart= QDateTime::currentDateTime();
85                                        while (DoStart) {
86                                            if (!cvSetChannel(Capture, Channel)) qDebug() << "cvSetChannel Error!";
87                                            frame= cvQueryFrame(Capture);
88                                            if (frame) {
89                                                if (MainForm->ui->QCBAutoBrightness->isChecked()) {
90                                                    int Brightness= BrightnessOfAPixel(frame);
91                                                    Brightness= ((Brightness * 200 / 256) - 100) * -1;
92                                                    IplImage *frame2= ContrastBrightness(frame, 0, Brightness); {
93                                                        cvCopyImage(frame2, frame);
94                                                    }{
95                                                        cvReleaseImage(&frame2);
96                                                    }
97                                                } else {
98                                                    IplImage *frame2= ContrastBrightness(frame, MainForm->ui->QHSContrast->value(), MainForm->ui->QHSBrightness->value()); {
99                                                        cvCopyImage(frame2, frame);
100                                                    }{
101                                                        cvReleaseImage(&frame2);
102                                                    }
103                                                }
104                                                if (MainForm->ui->QCBShowDateTime->isChecked()) cvPutText(frame, QDateTime::currentDateTime().toString("dd-MM-yyyy hh:mm:ss").toAscii(), cvPoint(10, 20), &font, cvScalar(255, 255, 255));
105                                                if (MainForm->ui->QRBRotate90->isChecked()) {
106                                                    IplImage *frame2= Rotate(frame, 90); {
107                                                        cvCopyImage(frame2, frame);
108                                                    }{
109                                                        cvReleaseImage(&frame2);
110                                                    }
111                                                } else if (MainForm->ui->QRBRotate180->isChecked()) {
112                                                    IplImage *frame2= Rotate(frame, 180); {
113                                                        cvCopyImage(frame2, frame);
114                                                    }{
115                                                        cvReleaseImage(&frame2);
116                                                    }
117                                                } else if (MainForm->ui->QRBRotate270->isChecked()) {
118                                                    IplImage *frame2= Rotate(frame, 270); {
119                                                        cvCopyImage(frame2, frame);
120                                                    }{
121                                                        cvReleaseImage(&frame2);
122                                                    }
123                                                }
124                                                if (ExternalFrame) cvShowImage("Frame", frame);
125                                                QImage Image(frame->width, frame->height, QImage::Format_RGB888);
126                                                const unsigned char *data= NULL;
127                                                data= (unsigned char*)(frame->imageData);
128                                                Image= QImage(data, frame->width, frame->height, frame->widthStep, QImage::Format_RGB888);
129                                                if (DoStart) emit SendNewImage(Image);
130
131                                                AVFrame *pAVFrame= avcodec_alloc_frame();
132                                                uint8_t *pBuffer= (uint8_t*)malloc(avpicture_get_size(PIX_FMT_YUV420P, Width, Height)); {
133                                                    avpicture_fill((AVPicture*)pAVFrame, pBuffer, PIX_FMT_YUV420P, Width, Height);
134                                                    IplImageToAVFrame(frame, pAVFrame, Width, Height, PIX_FMT_YUV420P);
135                                                    pAVFrame->pts= Frames;
136                                                    int OutSize= avcodec_encode_video(pCodecCtx, pOutBuffer, BYTEPIC, pAVFrame);
137                                                    if (OutSize> 0) {
138                                                        AVPacket Packet;
139                                                        av_init_packet(&Packet);
140                                                        //Packet.pts= Frames;
141                                                        if (pCodecCtx->coded_frame->pts != AV_NOPTS_VALUE) {
142                                                            Packet.pts= av_rescale_q(pCodecCtx->coded_frame->pts, pCodecCtx->time_base, pVideoStream->time_base);
143                                                        }
144                                                        if (pCodecCtx->coded_frame->key_frame) Packet.flags |= AV_PKT_FLAG_KEY;
145                                                        Packet.stream_index= pVideoStream->index;
146                                                        Packet.data= pOutBuffer;
147                                                        Packet.size= OutSize;
148                                                        if (av_interleaved_write_frame(pFormatCtx, &Packet)!= 0) qDebug() << "av_interleaved_write_frame Error!";
149
150
151                                                        DynBuffer *d= (DynBuffer*)pFormatCtx->pb->opaque;
152                                                        qDebug() << d->buffer << pFormatCtx->pb->buffer << pFormatCtx->pb->pos;
153                                                        /*QByteArray QBAByteIn((const char*)d->buffer, d->pos);
154                                                        QFMPGFileOut.write(QBAByteIn);
155                                                        d->pos= d->size= 0;*/
156
157
158                                                    }
159                                                    Frames++;
160                                                    if (Frames> pCodecCtx->time_base.den / pCodecCtx->time_base.num * 5) break;
161                                                }{
162                                                    av_free(pAVFrame);
163                                                    free(pBuffer);
164                                                }
165
166
167                                            } else qDebug() << "QThCamera::run() frame= false";
168                                        }
169                                        qDebug() << Frames / QDTStart.secsTo(QDateTime::currentDateTime());
170                                    }{
171                                        free(pOutBuffer);
172                                    }
173                                    if (av_write_trailer(pFormatCtx)!= 0) qDebug() << "av_write_trailer Error!"; // Crash with H264!!!
174                                    uint8_t *pDynBuffer; {
175                                        DynBuffer *d= (DynBuffer*)pFormatCtx->pb->opaque;
176                                        qDebug() << d->buffer << pFormatCtx->pb->opaque << d->allocated_size;
177                                        //QByteArray QBAByteIn((const char*)d->buffer, d->pos);
178                                        //d->pos= d->size= 0;*/
179                                        int pDynBufferLen= avio_close_dyn_buf(pFormatCtx->pb, &pDynBuffer);
180                                        qDebug() << pDynBufferLen << pDynBuffer;
181                                        //QByteArray QBAByteIn((const char*)pDynBuffer, pDynBufferLen);
182                                        //QFMPGFileOut.write(QBAByteIn);
183                                    }{
184                                        av_free(pDynBuffer);
185                                    }
186                                }
187                                QFMPGFileOut.close();
188                            } else qDebug() << "QFMPGFileOut.open() Error!";
189                            avcodec_close(pVideoStream->codec);
190                        }
191                    }
192                    for (int count= 0; (unsigned)count< pFormatCtx->nb_streams; count++) {
193                        av_freep(&pFormatCtx->streams[count]->codec);
194                        av_freep(&pFormatCtx->streams[count]);
195                    }
196                }
197                av_free(pFormatCtx);
198            }
199        }
200        cvReleaseCapture(&Capture);
201        if (ExternalFrame) cvDestroyWindow("Frame");
202    }
203    qDebug() << "QThCamera::run() stop";
204}
205
206IplImage* QThCamera::Rotate(IplImage *src, int angle) {
207    IplImage *dest= cvCloneImage(src);
208    CvPoint2D32f center;
209    center.x= dest->width / 2;
210    center.y= dest->height / 2;
211    CvMat *mapMatrix= cvCreateMat(2, 3, CV_32FC1); {
212        cv2DRotationMatrix(center, angle, 1.0, mapMatrix);
213        cvWarpAffine(src, dest, mapMatrix, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
214    }{
215        cvReleaseMat(&mapMatrix);
216    }
217    return dest;
218}
219
220/*IplImage* QThCamera::Rotate(const IplImage *img, int angle) {
221    IplImage *newImg;
222    int newWidth, newHeight;
223    int rectX, rectY;
224    if (angle == -45 || angle == 45) {
225        newWidth= (int) ((img->width + img->height) / sqrt(2.0));
226        newHeight= (int) ((img->width + img->height) / sqrt(2.0));
227    } else if (angle == -90 || angle == 90) {
228        if (img->width > img->height) {
229            newWidth = img->width;
230            newHeight = img->width;
231        } else {
232            newWidth= img->height;
233            newHeight= img->height;
234        }
235    } else {
236        newWidth = img->width;
237        newHeight = img->height;
238    }
239    newImg= cvCreateImage(cvSize(newWidth, newHeight), img->depth, img->nChannels);
240    cvSetZero(newImg);
241    rectX = (int) ((newWidth - img->width) / 2);
242    rectY = (int) ((newHeight - img->height) / 2);
243    CvRect rect = cvRect(rectX, rectY, img->width, img->height);
244    cvSetImageROI(newImg, rect);
245    cvResize(img, newImg);
246    cvResetImageROI(newImg);
247    IplImage *rotatedImg = cvCreateImage(cvGetSize(newImg), IPL_DEPTH_8U, img -> nChannels);
248    CvPoint2D32f center;
249    int xPos, yPos;
250    xPos = (int) newWidth / 2;
251    yPos = (int) newHeight / 2;
252    CvMat *mapMatrix = cvCreateMat(2, 3, CV_32FC1);
253    center.x = xPos;
254    center.y = yPos;
255    cv2DRotationMatrix(center, angle, 1.0, mapMatrix);
256    cvWarpAffine(newImg, rotatedImg, mapMatrix);
257    return rotatedImg;
258}*/
259
260int QThCamera::BrightnessOfAPixel(IplImage *src) {
261    int Result= -1;
262    IplImage *hsv= cvCloneImage(src); {
263        cvCvtColor(src, hsv, CV_BGR2HSV);
264        int x= 0, y= 0;
265        QVector <int>QVResults;
266        if (src->nChannels== 3) {
267            IplImage *ThirthChannelImage= cvCreateImage(cvGetSize(src), 8, 1); {
268                cvSplit(hsv, NULL, NULL, ThirthChannelImage, NULL);
269                while (true) {
270                    if (x< cvGetSize(src).width && y< cvGetSize(src).height) {
271                        QVResults.append(cvRound(cvGetReal2D(ThirthChannelImage, x, y)));
272                        x= x+ 32;
273                        y= y+ 32;
274                    } else break;
275                }
276            }{
277                cvReleaseImage(&ThirthChannelImage);
278            }
279        } else {
280            while (true) {
281                if (x< cvGetSize(src).width && y< cvGetSize(src).height) {
282                    QVResults.append(cvRound(cvGetReal2D(hsv, x, y)));
283                    x= x+ 32;
284                    y= y+ 32;
285                } else break;
286            }
287        }
288        if (QVResults.count()> 0) Result= QVResults[0];
289        if (QVResults.count()> 1) {
290            for (int count= 1; count< QVResults.count(); count++) Result+= QVResults[count];
291            Result= Result / QVResults.count();
292        }
293    } {
294        cvReleaseImage(&hsv);
295    }
296    return Result;
297}
298
299IplImage* QThCamera::ContrastBrightness(IplImage *src, int Contrast, int Brightness) {
300    if(Contrast> 100) Contrast= 100;
301    if(Contrast< -100) Contrast= -100;
302    if(Brightness> 100) Brightness= 100;
303    if(Brightness< -100) Brightness= -100;
304    uchar UserData[256];
305    CvMat* MultiChannel2DMatrix;
306    IplImage *dest= cvCloneImage(src);
307    IplImage *gray= cvCreateImage(cvGetSize(src), src->depth, 1); {
308        MultiChannel2DMatrix= cvCreateMatHeader(1, 256, CV_8UC1);
309        cvSetData(MultiChannel2DMatrix, UserData, 0);
310        if(Contrast> 0) {
311            double delta= 127. * Contrast / 100;
312            double a= 255. / (255. - delta * 2);
313            double b= a * (Brightness - delta);
314            for(int count= 0; count< 256; count++) {
315                int v= cvRound(a * count + b);
316                if (v< 0) v= 0;
317                if (v> 255) v= 255;
318                UserData[count]= v;
319            }
320        } else {
321            double delta= -128. * Contrast / 100;
322            double a= (256. - delta * 2) / 255.;
323            double b= a * Brightness + delta;
324            for (int count= 0; count< 256; count++) {
325                int v= cvRound(a * count + b);
326                if (v< 0) v= 0;
327                if (v> 255) v= 255;
328                UserData[count]= v;
329            }
330        }
331        if (src->nChannels== 3) {
332            IplImage *R= cvCreateImage(cvGetSize(src), src->depth, 1);
333            IplImage *G= cvCreateImage(cvGetSize(src), src->depth, 1);
334            IplImage *B= cvCreateImage(cvGetSize(src), src->depth, 1); {
335                cvCvtPixToPlane(src, R, G, B, NULL);
336                cvLUT(R, R, MultiChannel2DMatrix);
337                cvLUT(G, G, MultiChannel2DMatrix);
338                cvLUT(B, B, MultiChannel2DMatrix);
339                cvCvtPlaneToPix(R, G, B, NULL, dest);
340            }{
341                cvReleaseImage(&R);
342                cvReleaseImage(&G);
343                cvReleaseImage(&B);
344            }
345        } else cvLUT(gray, dest, MultiChannel2DMatrix);
346    }{
347        cvReleaseImage(&gray);
348        cvReleaseMat(&MultiChannel2DMatrix);
349    }
350    return dest;
351}
352