00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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
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
00149
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
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
00200
00201
00202
00203
00204
00205
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
00224
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'))
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
00298 establishConnection();
00299 NegotiationState = SendGET_EnteredAuth;
00300 return;
00301
00302
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'))
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
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
00494 AsyncSocket->write(send_buffer, std::strlen(send_buffer));
00495
00496
00497 }
00498
00499
00500
00501
00502
00503
00504
00505 bool mxcpcAsynchronousCameraLiveMxPEGFastStream::receiveHTTPHeader(void) {
00506
00507 char c;
00508
00509 if(HTTPHeaderBytesRead
00510 == MXCPC_ASYNCHRONOUSCAMERALIVEMXPEGFASTSTREAM_HEADERBUFFER_SIZE)
00511 return(false);
00512
00513
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))
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