Ticket #984: qthcamera.cpp

File qthcamera.cpp, 20.0 KB (added by mrdebug, 5 years ago)

It's a thread that grab images with opencv and uses ffmpeg to generate a mp4 file

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_RGB24, 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
24static int WritePacket(void *opaque, uint8_t *pBuffer, int pBufferSize) {
25    return ((QThCamera*)opaque)->QThPlayWritePacket(pBuffer, pBufferSize);
26}
27
28int QThCamera::QThPlayWritePacket(uint8_t *pBuffer, int pBufferSize) {
29    QByteArray QBAByteIn;
30    QBAByteIn.setRawData((const char*)pBuffer, pBufferSize);
31    FileOut->write(QBAByteIn);
32    qDebug() << pBufferSize;
33    return pBufferSize;
34}
35
36void QThCamera::run() {
37    FileOut= new QFile();
38    FileOut->setFileName("a.mp4");
39    FileOut->open(QIODevice::WriteOnly);
40    qDebug() << "QThCamera::run() start";
41
42    CvCapture *Capture= NULL;
43    Capture= cvCreateCameraCapture(Index, Width, Height);
44    if (!Capture) qDebug() << "cvCreateCameraCapture Error!";
45    else {
46        if (ExternalFrame) cvNamedWindow("Frame", CV_WINDOW_AUTOSIZE);
47        IplImage *frame= 0;
48        CvFont font;
49        cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5f, 0.5f);
50
51        int BUFFERSIZE= 32768;
52        qDebug() << BUFFERSIZE;
53        AVIOContext *pAVIOContext;
54        unsigned char *pBuffer= (unsigned char*)av_malloc(BUFFERSIZE * sizeof(uint8_t)); {
55            pAVIOContext= avio_alloc_context(pBuffer, BUFFERSIZE, 1, this, NULL, WritePacket, NULL);
56            if (pAVIOContext< 0) qDebug() << "Errore avio_alloc_context !!!";
57            else {
58
59
60                AVOutputFormat *pAVOutputFormat= av_guess_format(NULL, FileOut->fileName().toStdString().c_str(), NULL); // CODEC_ID_H264 -> mp4; CODEC_ID_THEORA -> ogg; CODEC_ID_MPEG4 -> mpegts; CODEC_ID_VP8 -> webm
61                if (!pAVOutputFormat) {
62                    qDebug() << "Could not set output format, using MPEG.";
63                    pAVOutputFormat= av_guess_format("mpeg", NULL, NULL);
64                }
65                if (!pAVOutputFormat) qDebug() << "av_guess_format Error!";
66                else {
67                    AVFormatContext *pAVFormatContext;
68                    pAVFormatContext= avformat_alloc_context();
69                    if (!pAVFormatContext) qDebug() << "avformat_alloc_context Error!";
70                    else {
71                        pAVFormatContext->oformat= pAVOutputFormat;
72                        pAVFormatContext->pb= pAVIOContext;
73                        /*if (AVOutputFormat(&pAVFormatContext->pb, FileName.toStdString().c_str(), AVIO_FLAG_WRITE)< 0) qDebug() << "avio_open Error!";
74                        else {*/
75                            AVStream *pAVStream= avformat_new_stream(pAVFormatContext, 0);
76                            if (!pAVStream) qDebug() << "av_new_stream Error!";
77                            else {
78                                AVCodecContext *pAVCodecContext= pAVStream->codec;
79                                pAVCodecContext->codec_id= (CodecID)pAVOutputFormat->video_codec;
80                                pAVCodecContext->codec_type= AVMEDIA_TYPE_VIDEO;
81                                pAVCodecContext->bit_rate= 40000;
82                                pAVCodecContext->width= Width;
83                                pAVCodecContext->height= Height;
84                                pAVCodecContext->time_base.den= 25;
85                                pAVCodecContext->time_base.num= 1;
86                                pAVCodecContext->gop_size= 10;
87                                pAVCodecContext->pix_fmt= PIX_FMT_YUV420P;
88                                if (pAVFormatContext->oformat->flags & AVFMT_GLOBALHEADER) pAVCodecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
89                                if (pAVCodecContext->codec_id== CODEC_ID_H264) {
90                                    qDebug() << "CODEC_ID_H264";
91                                    pAVCodecContext->bit_rate= 500 * 1000;
92                                    pAVCodecContext->bit_rate_tolerance= 0;
93                                    pAVCodecContext->rc_max_rate= 0;
94                                    pAVCodecContext->rc_buffer_size= 0;
95                                    pAVCodecContext->gop_size= 40;
96                                    pAVCodecContext->max_b_frames= 3;
97                                    pAVCodecContext->b_frame_strategy= 1;
98                                    pAVCodecContext->coder_type= 1;
99                                    pAVCodecContext->me_cmp= 1;
100                                    pAVCodecContext->me_range= 16;
101                                    pAVCodecContext->qmin= 10;
102                                    pAVCodecContext->qmax= 51;
103                                    pAVCodecContext->scenechange_threshold= 40;
104                                    pAVCodecContext->flags|= CODEC_FLAG_LOOP_FILTER;
105                                    pAVCodecContext->me_method= ME_HEX;
106                                    pAVCodecContext->me_subpel_quality= 5;
107                                    pAVCodecContext->i_quant_factor= 0.71;
108                                    pAVCodecContext->qcompress= 0.6;
109                                    pAVCodecContext->max_qdiff= 4;
110                                    pAVCodecContext->flags2|= CODEC_FLAG2_FASTPSKIP;
111                                    pAVFormatContext->oformat->flags |= AVFMT_TS_NONSTRICT;
112                                } else if (pAVCodecContext->codec_id== CODEC_ID_THEORA) {
113                                    qDebug() << "CODEC_ID_THEORA";
114                                    //pAVCodecContext->extradata= av_malloc((void*)FF_INPUT_BUFFER_PADDING_SIZE);
115                                }
116                                av_dict_set(&pAVFormatContext->metadata, "title", "Titolo", 0);
117                                av_dump_format(pAVFormatContext, 0, NULL, 1);
118                                    if (avformat_write_header(pAVFormatContext, NULL)!= 0) qDebug() << "av_write_header Error!";
119                                    AVCodec *pCodec= avcodec_find_encoder(pAVCodecContext->codec_id);
120                                    if (!pCodec) qDebug() << "avcodec_find_encoder Error!";
121                                    else {
122                                        if (avcodec_open2(pAVCodecContext, pCodec, NULL)< 0) qDebug() << "avcodec_open Error!";
123                                        else {
124                                            int BYTEPIC= Width * Height * 3;
125                                            uint8_t *pOutBuffer= (uint8_t*)malloc(BYTEPIC); {
126                                                int Frames= 0;
127                                                QDateTime QDTStart= QDateTime::currentDateTime();
128                                                while (DoStart) {
129                                                    if (!cvSetChannel(Capture, Channel)) qDebug() << "cvSetChannel Error!";
130                                                    frame= cvQueryFrame(Capture);
131                                                    if (frame) {
132                                                        Frames++;
133                                                        cvCvtColor(frame, frame, CV_BGR2RGB);
134                                                        if (MainForm->ui->QCBAutoBrightness->isChecked()) {
135                                                            int Brightness= BrightnessOfAPixel(frame);
136                                                            Brightness= ((Brightness * 200 / 256) - 100) * -1;
137                                                            IplImage *frame2= ContrastBrightness(frame, 0, Brightness); {
138                                                                cvCopyImage(frame2, frame);
139                                                            }{
140                                                                cvReleaseImage(&frame2);
141                                                            }
142                                                        } else {
143                                                            IplImage *frame2= ContrastBrightness(frame, MainForm->ui->QHSContrast->value(), MainForm->ui->QHSBrightness->value()); {
144                                                                cvCopyImage(frame2, frame);
145                                                            }{
146                                                                cvReleaseImage(&frame2);
147                                                            }
148                                                        }
149                                                        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));
150                                                        if (MainForm->ui->QRBRotate90->isChecked()) {
151                                                            IplImage *frame2= Rotate(frame, 90); {
152                                                                cvCopyImage(frame2, frame);
153                                                            }{
154                                                                cvReleaseImage(&frame2);
155                                                            }
156                                                        } else if (MainForm->ui->QRBRotate180->isChecked()) {
157                                                            IplImage *frame2= Rotate(frame, 180); {
158                                                                cvCopyImage(frame2, frame);
159                                                            }{
160                                                                cvReleaseImage(&frame2);
161                                                            }
162                                                        } else if (MainForm->ui->QRBRotate270->isChecked()) {
163                                                            IplImage *frame2= Rotate(frame, 270); {
164                                                                cvCopyImage(frame2, frame);
165                                                            }{
166                                                                cvReleaseImage(&frame2);
167                                                            }
168                                                        }
169                                                        if (ExternalFrame) cvShowImage("Frame", frame);
170                                                        QImage Image= QImage((unsigned char*)(frame->imageData), frame->width, frame->height, frame->widthStep, QImage::Format_RGB888);
171                                                        if (DoStart) emit SendNewImage(Image);
172                                                        AVFrame *pAVFrame= avcodec_alloc_frame();
173                                                        uint8_t *pBuffer= (uint8_t*)malloc(avpicture_get_size(PIX_FMT_YUV420P, Width, Height)); {
174                                                            avpicture_fill((AVPicture*)pAVFrame, pBuffer, PIX_FMT_YUV420P, Width, Height);
175                                                            IplImageToAVFrame(frame, pAVFrame, Width, Height, PIX_FMT_YUV420P);
176                                                            pAVFrame->pts= Frames;
177                                                            int OutSize= avcodec_encode_video(pAVCodecContext, pOutBuffer, BYTEPIC, pAVFrame);
178                                                            if (OutSize> 0) {
179                                                                AVPacket Packet;
180                                                                av_init_packet(&Packet);
181                                                                //Packet.pts= Frames;
182                                                                //if (pAVCodecContext->coded_frame->pts!= unsigned(AV_NOPTS_VALUE)) {
183                                                                    Packet.pts= av_rescale_q(pAVCodecContext->coded_frame->pts, pAVCodecContext->time_base, pAVStream->time_base);
184                                                                //}
185                                                                if (pAVCodecContext->coded_frame->key_frame) Packet.flags |= AV_PKT_FLAG_KEY;
186                                                                Packet.stream_index= pAVStream->index;
187                                                                Packet.data= pOutBuffer;
188                                                                Packet.size= OutSize;
189                                                                if (av_interleaved_write_frame(pAVFormatContext, &Packet)!= 0) qDebug() << "av_interleaved_write_frame Error!";
190                                                            }
191                                                        }{
192                                                            av_free(pAVFrame);
193                                                            free(pBuffer);
194                                                        }
195                                                    }
196                                                    if (QDTStart.secsTo(QDateTime::currentDateTime())> 3) break;
197                                                }
198                                                qDebug() << Frames / QDTStart.secsTo(QDateTime::currentDateTime());
199                                            }{
200                                                free(pOutBuffer);
201                                            }
202                                            avcodec_close(pAVCodecContext);
203                                        }
204                                    }
205                                    if (av_write_trailer(pAVFormatContext)!= 0) qDebug() << "av_write_trailer Error!";
206                                av_free(pAVStream);
207                            }
208                            //avio_close(pAVFormatContext->pb);
209                        //}
210                        av_free(pAVFormatContext);
211                    }
212                    //av_free(pAVOutputFormat);
213                }
214                cvReleaseCapture(&Capture);
215                if (ExternalFrame) cvDestroyWindow("Frame");
216
217
218            }
219        }
220
221
222    }
223    delete FileOut;
224    qDebug() << "QThCamera::run() stop";
225}
226
227IplImage* QThCamera::Rotate(IplImage *src, int angle) {
228    IplImage *dest= cvCloneImage(src);
229    CvPoint2D32f center;
230    center.x= dest->width / 2;
231    center.y= dest->height / 2;
232    CvMat *mapMatrix= cvCreateMat(2, 3, CV_32FC1); {
233        cv2DRotationMatrix(center, angle, 1.0, mapMatrix);
234        cvWarpAffine(src, dest, mapMatrix, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
235    }{
236        cvReleaseMat(&mapMatrix);
237    }
238    return dest;
239}
240
241/*IplImage* QThCamera::Rotate(const IplImage *img, int angle) {
242    IplImage *newImg;
243    int newWidth, newHeight;
244    int rectX, rectY;
245    if (angle == -45 || angle == 45) {
246        newWidth= (int) ((img->width + img->height) / sqrt(2.0));
247        newHeight= (int) ((img->width + img->height) / sqrt(2.0));
248    } else if (angle == -90 || angle == 90) {
249        if (img->width > img->height) {
250            newWidth = img->width;
251            newHeight = img->width;
252        } else {
253            newWidth= img->height;
254            newHeight= img->height;
255        }
256    } else {
257        newWidth = img->width;
258        newHeight = img->height;
259    }
260    newImg= cvCreateImage(cvSize(newWidth, newHeight), img->depth, img->nChannels);
261    cvSetZero(newImg);
262    rectX = (int) ((newWidth - img->width) / 2);
263    rectY = (int) ((newHeight - img->height) / 2);
264    CvRect rect = cvRect(rectX, rectY, img->width, img->height);
265    cvSetImageROI(newImg, rect);
266    cvResize(img, newImg);
267    cvResetImageROI(newImg);
268    IplImage *rotatedImg = cvCreateImage(cvGetSize(newImg), IPL_DEPTH_8U, img -> nChannels);
269    CvPoint2D32f center;
270    int xPos, yPos;
271    xPos = (int) newWidth / 2;
272    yPos = (int) newHeight / 2;
273    CvMat *mapMatrix = cvCreateMat(2, 3, CV_32FC1);
274    center.x = xPos;
275    center.y = yPos;
276    cv2DRotationMatrix(center, angle, 1.0, mapMatrix);
277    cvWarpAffine(newImg, rotatedImg, mapMatrix);
278    return rotatedImg;
279}*/
280
281int QThCamera::BrightnessOfAPixel(IplImage *src) {
282    int Result= -1;
283    IplImage *hsv= cvCloneImage(src); {
284        cvCvtColor(src, hsv, CV_BGR2HSV);
285        int x= 0, y= 0;
286        QVector <int>QVResults;
287        if (src->nChannels== 3) {
288            IplImage *ThirthChannelImage= cvCreateImage(cvGetSize(src), 8, 1); {
289                cvSplit(hsv, NULL, NULL, ThirthChannelImage, NULL);
290                while (true) {
291                    if (x< cvGetSize(src).width && y< cvGetSize(src).height) {
292                        QVResults.append(cvRound(cvGetReal2D(ThirthChannelImage, x, y)));
293                        x= x+ 32;
294                        y= y+ 32;
295                    } else break;
296                }
297            }{
298                cvReleaseImage(&ThirthChannelImage);
299            }
300        } else {
301            while (true) {
302                if (x< cvGetSize(src).width && y< cvGetSize(src).height) {
303                    QVResults.append(cvRound(cvGetReal2D(hsv, x, y)));
304                    x= x+ 32;
305                    y= y+ 32;
306                } else break;
307            }
308        }
309        if (QVResults.count()> 0) Result= QVResults[0];
310        if (QVResults.count()> 1) {
311            for (int count= 1; count< QVResults.count(); count++) Result+= QVResults[count];
312            Result= Result / QVResults.count();
313        }
314    } {
315        cvReleaseImage(&hsv);
316    }
317    return Result;
318}
319
320IplImage* QThCamera::ContrastBrightness(IplImage *src, int Contrast, int Brightness) {
321    if(Contrast> 100) Contrast= 100;
322    if(Contrast< -100) Contrast= -100;
323    if(Brightness> 100) Brightness= 100;
324    if(Brightness< -100) Brightness= -100;
325    uchar UserData[256];
326    CvMat* MultiChannel2DMatrix;
327    IplImage *dest= cvCloneImage(src);
328    IplImage *gray= cvCreateImage(cvGetSize(src), src->depth, 1); {
329        MultiChannel2DMatrix= cvCreateMatHeader(1, 256, CV_8UC1);
330        cvSetData(MultiChannel2DMatrix, UserData, 0);
331        if(Contrast> 0) {
332            double delta= 127. * Contrast / 100;
333            double a= 255. / (255. - delta * 2);
334            double b= a * (Brightness - delta);
335            for(int count= 0; count< 256; count++) {
336                int v= cvRound(a * count + b);
337                if (v< 0) v= 0;
338                if (v> 255) v= 255;
339                UserData[count]= v;
340            }
341        } else {
342            double delta= -128. * Contrast / 100;
343            double a= (256. - delta * 2) / 255.;
344            double b= a * Brightness + delta;
345            for (int count= 0; count< 256; count++) {
346                int v= cvRound(a * count + b);
347                if (v< 0) v= 0;
348                if (v> 255) v= 255;
349                UserData[count]= v;
350            }
351        }
352        if (src->nChannels== 3) {
353            IplImage *R= cvCreateImage(cvGetSize(src), src->depth, 1);
354            IplImage *G= cvCreateImage(cvGetSize(src), src->depth, 1);
355            IplImage *B= cvCreateImage(cvGetSize(src), src->depth, 1); {
356                cvCvtPixToPlane(src, R, G, B, NULL);
357                cvLUT(R, R, MultiChannel2DMatrix);
358                cvLUT(G, G, MultiChannel2DMatrix);
359                cvLUT(B, B, MultiChannel2DMatrix);
360                cvCvtPlaneToPix(R, G, B, NULL, dest);
361            }{
362                cvReleaseImage(&R);
363                cvReleaseImage(&G);
364                cvReleaseImage(&B);
365            }
366        } else cvLUT(gray, dest, MultiChannel2DMatrix);
367    }{
368        cvReleaseImage(&gray);
369        cvReleaseMat(&MultiChannel2DMatrix);
370    }
371    return dest;
372}
373