Ticket #984: qthcamera.cpp

File qthcamera.cpp, 20.0 KB (added by Denis, 15 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