Qt 4.8 #if added
[mardrone] / mardrone / dronelib / video.cpp
1 /*==================================================================
2   !
3   !  mardrone application AR-Drone for MeeGo
4
5   ! Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6   ! All rights reserved.
7   !
8   !  Author:Kate Alhola  kate.alhola@nokia.com
9   !
10   ! GNU Lesser General Public License Usage
11   ! This file may be used under the terms of the GNU Lesser
12   ! General Public License version 2.1 as published by the Free Software
13   ! Foundation and appearing in the file LICENSE.LGPL included in the
14   ! packaging of this file.  Please review the following information to
15   ! ensure the GNU Lesser General Public License version 2.1 requirements
16   ! will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17   !
18   !
19   !
20   *===================================================================*/
21 #include <stdio.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include "video.h"
27 #include <QNetworkConfigurationManager>
28 #include <QNetworkSession>
29 #include <QList>
30 #include <QGraphicsView>
31 #include <QDateTime>
32 #include <QDir>
33
34 #ifdef QT_IOS
35 #define NO_VIDEO
36 #endif
37
38 DroneVideo::DroneVideo()
39 {
40      droneHost.setAddress("192.168.1.1");
41      initialized=false;
42      m_idleImage=NULL;
43      videoThread=NULL;
44 }
45
46
47 void DroneVideo::frameSeqUpdated()
48 {
49     emit frameSeqChanged();
50 }
51
52 QImage* DroneVideo::idleImage() { return m_idleImage; }
53 void DroneVideo::setIdleImage(QImage *img)
54 {
55     m_idleImage=img;
56
57     if(m_idleImage && image) {
58         QPainter p(image);
59         p.drawImage(0,0,*m_idleImage);
60         update(boundingRect());
61     }
62 };
63
64 void DroneVideo::paint(QPainter *painter,const QStyleOptionGraphicsItem *option,
65                         QWidget *widget)
66  {
67     if(!initialized) { // We need initialize QImage here because we don't know display depth before
68
69         depth=painter->device()->depth();
70         qDebug() << "depth=" << depth;
71
72         if(depth>=24) {
73             image=new QImage(320,240, QImage::Format_RGB32);
74              image->fill(0x555555);
75         }
76         else {
77             image=new QImage(320,240, QImage::Format_RGB16);
78             image->fill(0x5555);
79         }
80         QPainter p(image);
81         if(m_idleImage) {
82             p.drawImage(0,0,*m_idleImage);
83         } else {
84           p.drawLine(0,0,image->width(),image->height());
85           p.drawLine(image->width(),0,0,image->height());
86         }
87         update(boundingRect());
88         videoThread=new VideoThread(this,droneHost,image);
89         connect(videoThread,SIGNAL(frameSeqChanged()),this,SLOT(frameSeqUpdated()));
90         initialized=true;
91     } else
92     painter->drawImage(boundingRect(),*image,image->rect());
93  };
94
95 QRectF DroneVideo::boundingRect() const
96 {
97     return QRectF(0.0,0.0,size().width(),size().height());
98 }
99
100
101 /*
102
103   VideoThread
104
105   */
106
107
108 VideoThread::VideoThread(DroneVideo *parentp,QHostAddress host,QImage *_image)
109 {
110     struct ip_mreq imreq;
111     QString my_ip;
112     my_ip="192.168.1.2";
113     image=_image;
114     qDebug() << "videoThread::videoThread";
115     stopped=false;
116     parent=parentp;
117     videoSock=new QUdpSocket();
118     if(!videoSock->bind(QHostAddress::Any,5555)) qDebug() << "VideoThread::VideoThread ** Cant Bind to port 5555 ***" << videoSock->errorString();
119     QList<QNetworkConfiguration> netconfs=QNetworkConfigurationManager().allConfigurations();
120     foreach (QNetworkConfiguration np,netconfs) {
121         qDebug() << "network Confifuration name " << np.name() << np.bearerName() << np.bearerTypeName();
122         QNetworkSession ns(np);
123         if(ns.interface().addressEntries().empty())
124             qDebug() << "network session " << ns.interface().humanReadableName() << "**NotConfig**";
125         else {
126             qDebug() << "network session " << ns.interface().humanReadableName() <<   ns.interface().addressEntries().first().ip();
127             // Ubuntu may give wlan0 as "Ethernet"
128             if((np.bearerName()==QString("WLAN")) || (ns.interface().humanReadableName()==QString("wlan0")) ) {
129                my_ip=ns.interface().addressEntries().first().ip().toString();
130                qDebug() << "My IP is " << my_ip;
131         }
132         }
133     }
134     // Qt 4.7.x
135     imreq.imr_multiaddr.s_addr=inet_addr("224.1.1.1");
136     imreq.imr_interface.s_addr=inet_addr(my_ip.toAscii());
137     setsockopt(videoSock->socketDescriptor(),IPPROTO_IP,IP_ADD_MEMBERSHIP,&imreq,sizeof(imreq));
138 #if QT_VERSION >= 0x040800
139     // Qt 4.8
140     if(!videoSock->joinMulticastGroup(QHostAddress("224.1.1.1")))
141         qDebug() << "VideoThread::VideoThread can't join multicast Group 224.1.1.1" << videoSock->errorString();
142 #endif
143     droneHost=host;
144     videoRec=FALSE;
145     videoFile=NULL;
146     start();
147
148 };
149
150
151 void VideoThread::run()
152 {
153 #define ACQ_WIDTH     320
154 #define ACQ_HEIGHT    240
155 #undef memset
156     memset(&controller,0,sizeof(controller));
157     memset(&picture,0,sizeof(picture));
158     pictureWidth= image->width();
159     pictureHeight=image->height();
160     int codec_type=UVLC_CODEC;
161     qDebug() << "videoThread::run()";
162     stateTimer=new QTimer();
163     connect(stateTimer,SIGNAL(timeout()),this,SLOT(timer()));
164     connect(videoSock,SIGNAL(readyRead()),this,SLOT(videoDataReady()));
165     qDebug() << "videoThread::run() 2";
166     luma_only=FALSE;
167     num_picture_decoded=0;
168     /// Picture configuration
169 #ifndef NO_VIDEO
170     picture.format        = PIX_FMT_YUV420P;
171     picture.width         = pictureWidth;
172     picture.height        = pictureHeight;
173     picture.framerate     = 30;
174     picture.y_buf         = (uint8_t*)(void*)vp_os_malloc((size_t) pictureWidth*pictureHeight );
175     picture.cr_buf        = (uint8_t*)vp_os_malloc( pictureWidth*pictureHeight/4 );
176     picture.cb_buf        = (uint8_t*)vp_os_malloc( pictureWidth*pictureHeight/4 );
177     picture.y_line_size   = pictureWidth;
178     picture.cb_line_size  = pictureWidth / 2;
179     picture.cr_line_size  = pictureWidth / 2;
180     picture.y_pad         = 0;
181     picture.c_pad         = 0;
182
183     qDebug() << "video_codec_open=" << video_codec_open(&controller, (codec_type_t)codec_type);
184 #endif
185     //stateTimer->start(1000);
186     qDebug() << "videoThread::run() initialized";
187     sendVideoPort("AT");
188     while(!stopped) {
189         exec();
190     }
191
192 }
193
194 void VideoThread::timer()
195 {
196   //  qDebug() << "thread Timer";
197
198 }
199
200 void VideoThread::sendVideoPort(QString cmd)
201 {
202     QByteArray dgram;
203     dgram=cmd.toLatin1();
204     qDebug() << "videoThread::sendCmd= " << cmd+"\n" << "to " << droneHost ;
205     videoSock->writeDatagram(dgram.data(),dgram.size(),droneHost,5555);
206 }
207
208 unsigned int VideoThread::getFrameSeq()
209 {
210     return frameSeq;
211 }
212
213 void VideoThread::setVideoRec(bool rec)
214 {
215     qDebug() << "VideoThread::setVideoRec" <<  rec;
216     QDateTime fileDate=QDateTime::currentDateTime();
217     if(!videoRec && rec) {
218         frameSeq=0;
219         videoFileName="dronerec"+fileDate.toString("yyyyMMddhhmm");
220         qDebug() << "videoFileName=" <<  videoFileName;
221         emit frameSeqChanged();
222     }
223     videoRec=rec;
224     if(!videoRec && videoFile) { // Stop recording
225         videoFile->close();
226         videoFile->~QFile();
227         videoFile=NULL;
228         videoFileName="";
229     }
230
231
232 }
233
234 bool VideoThread::getVideoRec()
235 {
236     return videoRec;
237 }
238
239 QString VideoThread::getVideoFileName()
240 {
241     return videoFileName;
242 }
243
244 void VideoThread::setVideoFileName(QString name)
245 {
246     videoFileName=name;
247 }
248
249 void VideoThread::setVideoPlay(bool play)
250 {
251     if(!videoPlay && play) frameSeq=0;
252         videoPlay=true;
253         videoRec=false;
254 }
255
256 bool VideoThread::getVideoPlay()
257 {
258     return videoPlay;
259 }
260
261
262
263
264 void VideoThread::videoDataReady()
265 {
266    qint64 l;
267    QByteArray videoData;
268
269    QHostAddress host;
270    quint16 port;
271    videoData.resize(videoSock->pendingDatagramSize ());
272    l=videoSock->readDatagram(videoData.data(),videoData.size(),&host,&port);
273 //   qDebug() << "videoThread::videoDataReady" <<" l=" << l << "from"  << host ;
274
275    if(videoRec && videoFile==NULL) {
276        // Open Video File
277    }
278
279    decodeTransform(videoData);
280
281 }
282
283 void VideoThread::decodeTransform(QByteArray &videoData)
284 {
285     controller.in_stream.bytes   = (uint32_t*)videoData.data();
286     controller.in_stream.used    = videoData.size();
287     controller.in_stream.size    = videoData.size();
288     controller.in_stream.index   = 0;
289     controller.in_stream.length  = 32;
290     controller.in_stream.code    = 0;
291
292     bool_t got_image = FALSE;
293     //qDebug() <<"VideoThread::decodeTransform" << controller.video_codec;
294 #ifndef NO_VIDEO
295     if(controller.video_codec!=NULL)  video_decode_blockline( &controller, &picture, &got_image );
296     if(videoRec && !videoFile) {// Start recording
297         qDebug() << "Record Video to " << QDir::current().absolutePath()  << videoFileName+".yuv" << " at " << picture.width << "x" << picture.height;
298         videoFile=new QFile(videoFileName+".yuv");
299         videoFile->open(QIODevice::WriteOnly);
300         if(videoFile->error()!=QFile::NoError) {
301             qDebug() << "Can't open Video file " << videoFileName << ".yuv" << videoFile->errorString();
302             videoFile->~QFile();
303             videoFile=NULL;
304             videoRec=false;
305         }
306     }
307      if(!videoRec && videoFile) { // Stop recording
308          videoFile->close();
309          videoFile->~QFile();
310          videoFile=NULL;
311          videoFileName="";
312      }
313     //else qDebug() << "No video controller";
314     //qDebug() <<"VideoThread::decodeTransform 2";
315     //video_decode_picture( &controller, &picture, &stream, &got_image );
316     if( got_image )
317         {
318           //  qDebug() <<"VideoThread::decodeTransform got image" << picture.width << picture.height << image->byteCount() << image->bytesPerLine();
319           // we got one picture
320           // out->size = 1;
321           frameSeq++;
322           picture.complete     = 1;
323           num_picture_decoded++;
324           if(videoFile && videoRec) {
325             videoFile->write((char*)picture.y_buf,picture.width*picture.height);
326             videoFile->write((char*)picture.cb_buf,picture.width*picture.height>>2);
327             videoFile->write((char*)picture.cr_buf,picture.width*picture.height>>2);
328           };
329           if(image->depth()<24)
330             vp_stages_YUV420P_to_RGB565(NULL,&picture,image->bits(),image->bytesPerLine());
331           else
332             vp_stages_YUV420P_to_ARGB32(NULL,&picture,image->bits(),image->bytesPerLine());
333           emit frameSeqChanged();
334
335        //   qDebug() << "pic " << num_picture_decoded;
336         }
337 #endif
338
339 };
340
341