int RemoteCameraHttp::Capture( Image &image ) { int content_length = GetResponse(); if ( content_length == 0 ) { Warning( "Unable to capture image, retrying" ); return( 1 ); } if ( content_length < 0 ) { Error( "Unable to get response" ); Disconnect(); return( -1 ); } switch( format ) { case JPEG : { if ( !image.DecodeJpeg( buffer.extract( content_length ), content_length, colours, subpixelorder ) ) { Error( "Unable to decode jpeg" ); Disconnect(); return( -1 ); } break; } case X_RGB : { if ( content_length != image.Size() ) { Error( "Image length mismatch, expected %d bytes, content length was %d", image.Size(), content_length ); Disconnect(); return( -1 ); } image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); break; } case X_RGBZ : { if ( !image.Unzip( buffer.extract( content_length ), content_length ) ) { Error( "Unable to unzip RGB image" ); Disconnect(); return( -1 ); } image.Assign( width, height, colours, subpixelorder, buffer, imagesize ); break; } default : { Error( "Unexpected image format encountered" ); Disconnect(); return( -1 ); } } return( 0 ); }
int cURLCamera::Capture( Image &image ) { bool frameComplete = false; /* MODE_STREAM specific variables */ bool SubHeadersParsingComplete = false; unsigned int frame_content_length = 0; std::string frame_content_type; bool need_more_data = false; int nRet; /* Grab the mutex to ensure exclusive access to the shared data */ lock(); while ( !frameComplete ) { /* If the work thread did a reset, reset our local variables */ if ( bReset ) { SubHeadersParsingComplete = false; frame_content_length = 0; frame_content_type.clear(); need_more_data = false; bReset = false; } if ( mode == MODE_UNSET ) { /* Don't have a mode yet. Sleep while waiting for data */ nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex); if ( nRet != 0 ) { Error("Failed waiting for available data condition variable: %s",strerror(nRet)); return -20; } } if ( mode == MODE_STREAM ) { /* Subheader parsing */ while( !SubHeadersParsingComplete && !need_more_data ) { size_t crlf_start, crlf_end, crlf_size; std::string subheader; /* Check if the buffer contains something */ if ( databuffer.empty() ) { /* Empty buffer, wait for data */ need_more_data = true; break; } /* Find crlf start */ crlf_start = memcspn(databuffer,"\r\n",databuffer.size()); if ( crlf_start == databuffer.size() ) { /* Not found, wait for more data */ need_more_data = true; break; } /* See if we have enough data for determining crlf length */ if ( databuffer.size() < crlf_start+5 ) { /* Need more data */ need_more_data = true; break; } /* Find crlf end and calculate crlf size */ crlf_end = memspn(((const char*)databuffer.head())+crlf_start,"\r\n",5); crlf_size = (crlf_start + crlf_end) - crlf_start; /* Is this the end of a previous stream? (This is just before the boundary) */ if ( crlf_start == 0 ) { databuffer.consume(crlf_size); continue; } /* Check for invalid CRLF size */ if ( crlf_size > 4 ) { Error("Invalid CRLF length"); } /* Check if the crlf is \n\n or \r\n\r\n (marks end of headers, this is the last header) */ if( (crlf_size == 2 && memcmp(((const char*)databuffer.head())+crlf_start,"\n\n",2) == 0) || (crlf_size == 4 && memcmp(((const char*)databuffer.head())+crlf_start,"\r\n\r\n",4) == 0) ) { /* This is the last header */ SubHeadersParsingComplete = true; } /* Copy the subheader, excluding the crlf */ subheader.assign(databuffer, crlf_start); /* Advance the buffer past this one */ databuffer.consume(crlf_start+crlf_size); Debug(7,"Got subheader: %s",subheader.c_str()); /* Find where the data in this header starts */ size_t subheader_data_start = subheader.rfind(' '); if ( subheader_data_start == std::string::npos ) { subheader_data_start = subheader.find(':'); } /* Extract the data into a string */ std::string subheader_data = subheader.substr(subheader_data_start+1, std::string::npos); Debug(8,"Got subheader data: %s",subheader_data.c_str()); /* Check the header */ if(strncasecmp(subheader.c_str(),content_length_match,content_length_match_len) == 0) { /* Found the content-length header */ frame_content_length = atoi(subheader_data.c_str()); Debug(6,"Got content-length subheader: %d",frame_content_length); } else if(strncasecmp(subheader.c_str(),content_type_match,content_type_match_len) == 0) { /* Found the content-type header */ frame_content_type = subheader_data; Debug(6,"Got content-type subheader: %s",frame_content_type.c_str()); } } /* Attempt to extract the frame */ if(!need_more_data) { if(!SubHeadersParsingComplete) { /* We haven't parsed all headers yet */ need_more_data = true; } else if ( ! frame_content_length ) { /* Invalid frame */ Error("Invalid frame: invalid content length"); } else if ( frame_content_type != "image/jpeg" ) { /* Unsupported frame type */ Error("Unsupported frame: %s",frame_content_type.c_str()); } else if(frame_content_length > databuffer.size()) { /* Incomplete frame, wait for more data */ need_more_data = true; } else { /* All good. decode the image */ image.DecodeJpeg(databuffer.extract(frame_content_length), frame_content_length, colours, subpixelorder); frameComplete = true; } } /* Attempt to get more data */ if(need_more_data) { nRet = pthread_cond_wait(&data_available_cond,&shareddata_mutex); if(nRet != 0) { Error("Failed waiting for available data condition variable: %s",strerror(nRet)); return -18; } need_more_data = false; } } else if(mode == MODE_SINGLE) { /* Check if we have anything */ if (!single_offsets.empty()) { if( (single_offsets.front() > 0) && (databuffer.size() >= single_offsets.front()) ) { /* Extract frame */ image.DecodeJpeg(databuffer.extract(single_offsets.front()), single_offsets.front(), colours, subpixelorder); single_offsets.pop_front(); frameComplete = true; } else { /* This shouldn't happen */ Error("Internal error. Attempting recovery"); databuffer.consume(single_offsets.front()); single_offsets.pop_front(); } } else { /* Don't have a frame yet, wait for the request complete condition variable */ nRet = pthread_cond_wait(&request_complete_cond,&shareddata_mutex); if(nRet != 0) { Error("Failed waiting for request complete condition variable: %s",strerror(nRet)); return -19; } } } else { /* Failed to match content-type */ Fatal("Unable to match Content-Type. Check URL, username and password"); } /* mode */ } /* frameComplete loop */ /* Release the mutex */ unlock(); if(!frameComplete) return -1; return 1; }