Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

mxcpcAsynchronousCameraLiveMxPEGFastStream.cpp

00001 //           ///          //                                        Mx clientSDK
00002 //          /////        ////                    Mx Crossplatform Client Library
00003 //         /// XXX     XXX ///
00004 //        ///    XXX XXX    ///     $RCSfile: mxcpcAsynchronousCameraLiveMxPEGFastStream.cpp,v $
00005 //       ///       XXX       ///     $Revision: 1.6 $
00006 //      ///      XXX XXX      ///     $Date: 2006/01/05 11:56:09 $
00007 //     ////    XXX     XXX    ////     $Author: cvs-kai $
00008 //    ////                     ////
00009 //   ////  M  O  B  O  T  I  X  ////////////////////////////////////////////////
00010 //  //// Security Vision Systems //////////////////////////////////////////////
00011 //                                                                          //
00012 //  Copyright (C) 2005 - 2006, MOBOTIX AG, Germany                         //
00013 //  This software is made available under the BSD licence. Please refer   //
00014 //  to the file LICENCE.TXT contained in this distribution for details.  //
00015 //                                                                      //
00016 //  /////////////////////////////////////////////////////////////////////
00017 
00018 
00019 
00020 #include <mxcpcAsynchronousCameraLiveMxPEGFastStream.h>
00021 #include <mxcpc_namespace.h>
00022 
00023 #include <cstdio>
00024 
00025 
00026 
00027 mxcpcAsynchronousCameraLiveMxPEGFastStream
00028  ::mxcpcAsynchronousCameraLiveMxPEGFastStream(
00029      const mxcpcIPAddress& camera_ip, 
00030      int camera_port,
00031      const mxcpcProxyConfiguration& camera_proxy_configuration,
00032      float fps
00033    ) : mxcpcCameraLiveMxPEGFastStream(camera_ip.getIP1(),
00034                                       camera_ip.getIP2(),
00035                                       camera_ip.getIP3(),
00036                                       camera_ip.getIP4(),
00037                                       camera_port,
00038                                       (int)fps)                                {
00039 
00040   CameraProxyConfiguration = camera_proxy_configuration;
00041   
00042   constructCommonStuff(camera_ip,
00043                        camera_port,
00044                        fps);
00045 }
00046                                               
00047 
00048 mxcpcAsynchronousCameraLiveMxPEGFastStream
00049  ::mxcpcAsynchronousCameraLiveMxPEGFastStream(const mxcpcIPAddress& camera_ip,
00050                                               int port,
00051                                               float fps)
00052     : mxcpcCameraLiveMxPEGFastStream(camera_ip.getIP1(),
00053                                      camera_ip.getIP2(),
00054                                      camera_ip.getIP3(),
00055                                      camera_ip.getIP4(),
00056                                      port,
00057                                      (int)fps)                                 {
00058 
00059   // camera proxy config implicitly defaults to "no proxy"
00060                                        
00061   constructCommonStuff(camera_ip,
00062                        port,
00063                        fps);
00064 }
00065 
00066 
00067 mxcpcAsynchronousCameraLiveMxPEGFastStream
00068  ::mxcpcAsynchronousCameraLiveMxPEGFastStream(const mxcpcIPAddress& camera_ip,
00069                                               int port,
00070                                               int fps)
00071     : mxcpcCameraLiveMxPEGFastStream(camera_ip.getIP1(),
00072                                      camera_ip.getIP2(),
00073                                      camera_ip.getIP3(),
00074                                      camera_ip.getIP4(),
00075                                      port,
00076                                      fps)                                      {
00077 
00078   // camera proxy config implicitly defaults to "no proxy"
00079   
00080   constructCommonStuff(camera_ip,
00081                        port,
00082                        (float)fps);
00083 }
00084 
00085 
00086 mxcpcAsynchronousCameraLiveMxPEGFastStream
00087  ::mxcpcAsynchronousCameraLiveMxPEGFastStream(int ip1,
00088                                               int ip2, 
00089                                               int ip3, 
00090                                               int ip4, 
00091                                               int port,
00092                                               int fps)
00093     : mxcpcCameraLiveMxPEGFastStream(ip1,
00094                                      ip2,
00095                                      ip3,
00096                                      ip4,
00097                                      port,
00098                                      fps)               {
00099 
00100   // camera proxy config implicitly defaults to "no proxy"
00101   
00102   constructCommonStuff(mxcpcIPAddress(ip1, ip1, ip3, ip4),
00103                        port,
00104                        (float)fps);
00105 }
00106     
00107                                    
00108 void mxcpcAsynchronousCameraLiveMxPEGFastStream
00109       ::constructCommonStuff(const mxcpcIPAddress& camera_ip, int camera_port,
00110                              float fps)                                        {
00111   
00112   CameraIP   = camera_ip;
00113   CameraPort = camera_port;
00114   FPS        = fps;
00115   if(FPS < 0.0f) FPS = 4.0f;
00116   
00117   mxcpc::sendStatusMsg((
00118           QString("AsynchronousCameraLiveMxPEGFastStream :")
00119           + QString(" opening faststream connection to camera ")
00120           + QString::number(CameraIP.getIP1())
00121           + QString(".")
00122           + QString::number(CameraIP.getIP2())
00123           + QString(".")
00124           + QString::number(CameraIP.getIP3())
00125           + QString(".")
00126           + QString::number(CameraIP.getIP4())
00127           + QString("...")
00128          ).toLatin1().constData());
00129   
00130   AsyncSocket = new QTcpSocket(0);
00131   QObject::connect(AsyncSocket, SIGNAL(connected(void)),
00132                    this, SLOT(processIncomingBytes(void)));
00133   QObject::connect(AsyncSocket, SIGNAL(readyRead(void)),
00134                    this, SLOT(processIncomingBytes(void)));                 
00135   
00136   establishConnection();
00137     
00138   HTTPHeaderBytesRead           = 0;
00139   HTTPHeaderSize                = 0;
00140   AuthenticationEntered         = false;
00141   AuthenticationDialogRaised    = false;
00142   AuthenticationDialogWasRaised = false;
00143   AuthenticationUser            = QString("");
00144   AuthenticationPassword        = QString("");
00145   
00146   NegotiationState              = SendGET_NoAuth;
00147   HTTPNegotiationMode           = true;
00148   // negotiation will be initiated by the socket's connected() signal 
00149   // activating our processIncomingBytes() slot
00150 }
00151 
00152 
00153 mxcpcAsynchronousCameraLiveMxPEGFastStream
00154  ::~mxcpcAsynchronousCameraLiveMxPEGFastStream() {
00155          
00156   mxcpc::sendStatusMsg((
00157           QString("AsynchronousCameraLiveMxPEGFastStream :")
00158           + QString(" closing faststream connection to camera ")
00159           + QString::number(CameraIP.getIP1())
00160           + QString(".")
00161           + QString::number(CameraIP.getIP2())
00162           + QString(".")
00163           + QString::number(CameraIP.getIP3())
00164           + QString(".")
00165           + QString::number(CameraIP.getIP4())
00166           + QString(".")
00167          ).toLatin1().constData()); 
00168    
00169   delete AsyncSocket;
00170 }
00171 
00172 
00173 
00174 int mxcpcAsynchronousCameraLiveMxPEGFastStream
00175      ::fetchBytes(unsigned char *buffer, int num) {
00176   
00177   int result;
00178   
00179   result = AsyncSocket->read((char *)buffer, num);
00180   if(result < 0) {
00181    
00182     // ERROR CONDITION !!! PROCESS MORE THOROUGHLY!!!
00183     result = 0;
00184   }
00185   
00186   return(result);
00187 }
00188 
00189 
00190 bool mxcpcAsynchronousCameraLiveMxPEGFastStream::stillUp(void) {
00191 
00192   std::printf("*** AsynchronousCameraLiveMxPEGFastStream::stillUp() "
00193               "not yet implemented !!! ***");
00194   std::exit(666);
00195 }
00196 
00197 
00198 /*!
00199  *  \param timeout_msecs
00200  *  If not <tt>-1</tt> the wait operation will time out after the number of
00201  *  milliseconds specified.
00202  *
00203  *  \returns
00204  *  <tt>true</tt> if data is available, and <tt>false</tt> in case of error or
00205  *  timeout
00206  */
00207 bool mxcpcAsynchronousCameraLiveMxPEGFastStream
00208       ::waitForBytes(int timeout_msecs)         {
00209    
00210   return(AsyncSocket->waitForReadyRead(timeout_msecs));
00211   
00212 }
00213 
00214 
00215 bool mxcpcAsynchronousCameraLiveMxPEGFastStream
00216       ::isAuthenticationDialogRaised(void)    {
00217         
00218   return(AuthenticationDialogRaised);
00219 }
00220 
00221 
00222 /*!
00223  *  If the dialog is currently raised the method will return <tt>true</tt> and
00224  *  the internal raise flag will not be reset.
00225  */
00226 bool mxcpcAsynchronousCameraLiveMxPEGFastStream
00227       ::wasAuthenticationDialogRaised(void)    {
00228         
00229   bool result;
00230         
00231   result = AuthenticationDialogWasRaised;
00232   
00233   if(!AuthenticationDialogRaised) AuthenticationDialogWasRaised = false;
00234   
00235   return(result);
00236 }
00237 
00238 
00239 void mxcpcAsynchronousCameraLiveMxPEGFastStream::processIncomingBytes(void) {
00240   
00241   int first_carriage_return;
00242   
00243   if(HTTPNegotiationMode) {
00244     
00245     for(;;) {
00246 
00247       switch(NegotiationState) {
00248       
00249        case SendGET_NoAuth:
00250          sendGETRequest();
00251          NegotiationState = ReceiveResponseHeader_NoAuth;
00252          break;
00253 
00254        case ReceiveResponseHeader_NoAuth:
00255          if(!receiveHTTPHeader()) return;
00256          
00257          first_carriage_return = 0;
00258          while(   (HTTPHeaderBuffer[first_carriage_return] != '\r')
00259                && (HTTPHeaderBuffer[first_carriage_return] != '\n'))  // be safe
00260            first_carriage_return++;
00261          if((first_carriage_return >= 2)
00262             && !std::strncmp(&HTTPHeaderBuffer[first_carriage_return - 2],
00263                              "OK", 2))                                     {   
00264            NegotiationState = NegotiationSucceeded;
00265          }
00266          else if((first_carriage_return >= 12)
00267                  && !std::strncmp(&HTTPHeaderBuffer[first_carriage_return - 12],
00268                                   "Unauthorized", 12))                         {
00269            AsyncSocket->disconnectFromHost();
00270            emit authenticationRequest(QString("Camera <b>")
00271                                       + QString::number(CameraIP.getIP1())
00272                                       + QString(".")
00273                                       + QString::number(CameraIP.getIP2())
00274                                       + QString(".")
00275                                       + QString::number(CameraIP.getIP3())
00276                                       + QString(".")
00277                                       + QString::number(CameraIP.getIP4())
00278                                       + QString("</b> ")
00279                                       + QString("requires you to authenticate ")
00280                                       + QString("for live stream access."));
00281            NegotiationState = RaisedAuthenticationDialog;
00282          }
00283          else {
00284            NegotiationState = NegotiationFailed;
00285          }
00286          break;
00287          
00288        case RaisedAuthenticationDialog:
00289          AuthenticationEntered = false;
00290          AuthenticationDialogRaised = true;
00291          AuthenticationDialogWasRaised = true;
00292          NegotiationState = WaitForAuthenticationDialog;
00293          break;
00294   
00295        case WaitForAuthenticationDialog:
00296          if(!AuthenticationEntered) return;
00297          // AuthenticationDialogRaised is false again.
00298          establishConnection();
00299          NegotiationState = SendGET_EnteredAuth;
00300          return;   // SendGET_EnteredAuth will be reached by the socket's
00301                    // conected() signal activating us (processIncomingBytes())
00302                    // again
00303          
00304        case SendGET_EnteredAuth:
00305          sendGETRequest(AuthenticationUser.toLatin1().constData(),
00306                         AuthenticationPassword.toLatin1().constData());
00307          NegotiationState = ReceiveResponseHeader_EnteredAuth;
00308          break;
00309          
00310        case ReceiveResponseHeader_EnteredAuth:
00311          if(!receiveHTTPHeader()) return;
00312          
00313          first_carriage_return = 0;
00314          while(   (HTTPHeaderBuffer[first_carriage_return] != '\r')
00315                && (HTTPHeaderBuffer[first_carriage_return] != '\n'))  // be safe
00316            first_carriage_return++;
00317          if((first_carriage_return >= 2)
00318             && !std::strncmp(&HTTPHeaderBuffer[first_carriage_return - 2],
00319                              "OK", 2))                                         {
00320            mxcpc::sendStatusMsg((
00321                    QString("AsynchronousCameraLiveMxPEGFastStream :")
00322                    + QString(" user '")
00323                    + AuthenticationUser
00324                    + QString("' successfully authenticated for live stream ")
00325                    + QString("access to camera ")
00326                    + QString::number(CameraIP.getIP1())
00327                    + QString(".")
00328                    + QString::number(CameraIP.getIP2())
00329                    + QString(".")
00330                    + QString::number(CameraIP.getIP3())
00331                    + QString(".")
00332                    + QString::number(CameraIP.getIP4())
00333                    + QString(".")
00334                   ).toLatin1().constData());
00335            NegotiationState = NegotiationSucceeded;
00336          }
00337          else if((first_carriage_return >= 12)
00338                  && !std::strncmp(&HTTPHeaderBuffer[first_carriage_return - 12],
00339                                   "Unauthorized", 12))                         {
00340            mxcpc::sendStatusMsg((
00341                    QString("AsynchronousCameraLiveMxPEGFastStream :")
00342                    + QString(" *** user '")
00343                    + AuthenticationUser
00344                    + QString("' failed to authenticate for live stream ")
00345                    + QString("access to camera ")
00346                    + QString::number(CameraIP.getIP1())
00347                    + QString(".")
00348                    + QString::number(CameraIP.getIP2())
00349                    + QString(".")
00350                    + QString::number(CameraIP.getIP3())
00351                    + QString(".")
00352                    + QString::number(CameraIP.getIP4())
00353                    + QString(" ***")
00354                   ).toLatin1().constData());
00355            emit authenticationRequest(QString("Camera <b>")
00356                                       + QString::number(CameraIP.getIP1())
00357                                       + QString(".")
00358                                       + QString::number(CameraIP.getIP2())
00359                                       + QString(".")
00360                                       + QString::number(CameraIP.getIP3())
00361                                       + QString(".")
00362                                       + QString::number(CameraIP.getIP4())
00363                                       + QString("</b> ")
00364                                       + QString("rejected your authentication ")
00365                                       + QString("request. Please try again."));
00366            NegotiationState = RaisedAuthenticationDialog;
00367          }
00368          else {
00369            NegotiationState = NegotiationFailed;
00370          }
00371          break;
00372          
00373        case NegotiationSucceeded:
00374          mxcpc::sendStatusMsg((
00375                  QString("AsynchronousCameraLiveMxPEGFastStream :")
00376                  + QString(" receiving faststream from camera ")
00377                  + QString::number(CameraIP.getIP1())
00378                  + QString(".")
00379                  + QString::number(CameraIP.getIP2())
00380                  + QString(".")
00381                  + QString::number(CameraIP.getIP3())
00382                  + QString(".")
00383                  + QString::number(CameraIP.getIP4())
00384                  + QString(".")
00385                 ).toLatin1().constData());
00386          HTTPNegotiationMode = false;
00387          if(AsyncSocket->bytesAvailable()) emit bytesAvailable();
00388          return;
00389          
00390        case NegotiationFailed:
00391        default:
00392          return;
00393       }
00394     }
00395   }
00396   
00397   else {
00398    
00399     emit bytesAvailable();
00400   }
00401 }
00402 
00403 
00404 void mxcpcAsynchronousCameraLiveMxPEGFastStream
00405       ::processAuthentication(const QString& user, const QString& password) {
00406 
00407   AuthenticationUser         = user;
00408   AuthenticationPassword     = password;
00409   
00410   AuthenticationDialogRaised = false;
00411   AuthenticationEntered      = true;
00412   
00413   processIncomingBytes();
00414 }
00415 
00416 
00417 void mxcpcAsynchronousCameraLiveMxPEGFastStream
00418       ::processAuthenticationCancellation(void) {
00419   
00420   AuthenticationDialogRaised = false;
00421 }
00422 
00423 
00424 void mxcpcAsynchronousCameraLiveMxPEGFastStream::establishConnection(void) {
00425 
00426   char txt[100];
00427   
00428   if(CameraProxyConfiguration.proxyUsed()) {
00429     std::sprintf(txt, "%d.%d.%d.%d", 
00430                  CameraProxyConfiguration.serverIP().getIP1(),
00431                  CameraProxyConfiguration.serverIP().getIP2(),
00432                  CameraProxyConfiguration.serverIP().getIP3(),
00433                  CameraProxyConfiguration.serverIP().getIP4());
00434                                      
00435     AsyncSocket->connectToHost(QString(txt), 
00436                                CameraProxyConfiguration.serverPort());
00437   }
00438   else {
00439     std::sprintf(txt, "%d.%d.%d.%d", CameraIP.getIP1(),
00440                                      CameraIP.getIP2(),
00441                                      CameraIP.getIP3(),
00442                                      CameraIP.getIP4());
00443     AsyncSocket->connectToHost(QString(txt), CameraPort);
00444   }
00445 }
00446 
00447 
00448 void mxcpcAsynchronousCameraLiveMxPEGFastStream
00449       ::sendGETRequest(const char *user, 
00450                        const char *password) {
00451 
00452   char send_buffer[1024];
00453   char txt_buffer[110], big_txt_buffer[200];
00454   
00455   // compose HTTP GET request... 
00456   if(!CameraProxyConfiguration.proxyUsed()) {
00457     std::sprintf(send_buffer, 
00458                  "GET /control/faststream.jpg?noaudio&fps=%f HTTP/1.0\r\n",
00459                  FPS);
00460   }
00461   else {
00462     std::sprintf(send_buffer, 
00463                  "GET http://%d.%d.%d.%d:%d/control/faststream.jpg"
00464                  "?noaudio&fps=%f HTTP/1.0\r\n",
00465                  CameraIP.getIP1(),
00466                  CameraIP.getIP2(),
00467                  CameraIP.getIP3(),
00468                  CameraIP.getIP4(),
00469                  CameraPort,
00470                  FPS);
00471   }
00472   if(user && password && (std::strlen(user) + std::strlen(password) < 100)) {
00473     std::sprintf(txt_buffer, "%s:%s", user, password);
00474     mxcpc::encode_base64((unsigned char *)txt_buffer, std::strlen(txt_buffer),
00475                          (unsigned char *)big_txt_buffer);
00476     std::strcat(send_buffer, "Authorization: BASIC ");
00477     std::strcat(send_buffer, big_txt_buffer);
00478     std::strcat(send_buffer, "\r\n");         
00479   }
00480   if(CameraProxyConfiguration.proxyUsed()) {
00481     std::strcat(send_buffer, "Host: ");
00482     std::sprintf(big_txt_buffer, "%d.%d.%d.%d:%d",
00483                  CameraIP.getIP1(),
00484                  CameraIP.getIP2(),
00485                  CameraIP.getIP3(),
00486                  CameraIP.getIP4(),
00487                  CameraPort);
00488     std::strcat(send_buffer, big_txt_buffer);
00489     std::strcat(send_buffer, "\r\n");      
00490   }
00491   std::strcat(send_buffer, "\r\n");              
00492   
00493   // send GET request...
00494   AsyncSocket->write(send_buffer, std::strlen(send_buffer));
00495     // We don't do any error checking here. Errors will be detected via the
00496     // stream connection timeout detection done by the superior context... 
00497 }   
00498 
00499 
00500 /*!
00501  *  \returns <tt>true</tt> if the complete header has successfully been read 
00502  *           into the buffer, or <tt>false</tt> if header bytes are still
00503  *           missing. 
00504  */
00505 bool mxcpcAsynchronousCameraLiveMxPEGFastStream::receiveHTTPHeader(void) {
00506 
00507   char c;
00508   
00509   if(HTTPHeaderBytesRead 
00510       == MXCPC_ASYNCHRONOUSCAMERALIVEMXPEGFASTSTREAM_HEADERBUFFER_SIZE)
00511     return(false);
00512       // buffer is full - "dead end" will be resolved by timeout strategy of
00513       // superior context
00514   
00515   while(AsyncSocket->read(&c, 1) == 1) {
00516     
00517     HTTPHeaderBuffer[HTTPHeaderBytesRead] = c;
00518     HTTPHeaderBytesRead++;
00519     
00520     if(   ((HTTPHeaderBytesRead >= 2) 
00521            && !std::strncmp(&HTTPHeaderBuffer[HTTPHeaderBytesRead - 2], 
00522                             "\n\n", 2))   // old camera software does it wrong
00523        || ((HTTPHeaderBytesRead >= 4) 
00524            && !std::strncmp(&HTTPHeaderBuffer[HTTPHeaderBytesRead - 4], 
00525                             "\r\n\r\n", 4)))                            {
00526                             
00527       HTTPHeaderSize = HTTPHeaderBytesRead;
00528       HTTPHeaderBytesRead = 0;
00529       return(true);
00530     }
00531     else {
00532       if(HTTPHeaderBytesRead 
00533           == MXCPC_ASYNCHRONOUSCAMERALIVEMXPEGFASTSTREAM_HEADERBUFFER_SIZE)
00534       return(false);
00535     }
00536   }
00537   
00538   return(false);
00539 }
00540 

Generated on Fri Jan 20 13:33:31 2006 for mxcpc by  doxygen 1.4.4