| 1 | #include "qthcamera.h"
|
|---|
| 2 |
|
|---|
| 3 | QThCamera::QThCamera(QObject *parent) : QThread(parent) {
|
|---|
| 4 | MainForm= (QFMainForm*)parent;
|
|---|
| 5 | DoStart= true;
|
|---|
| 6 | }
|
|---|
| 7 |
|
|---|
| 8 | QThCamera::~QThCamera() {
|
|---|
| 9 | DoStart= false;
|
|---|
| 10 | while (this->isRunning()) msleep(10);
|
|---|
| 11 | qDebug() << "QThCamera::~QThCamera()";
|
|---|
| 12 | }
|
|---|
| 13 |
|
|---|
| 14 | void 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 |
|
|---|
| 24 | typedef 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 |
|
|---|
| 31 | void 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 |
|
|---|
| 206 | IplImage* 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 |
|
|---|
| 260 | int 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 |
|
|---|
| 299 | IplImage* 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 |
|
|---|