#define IO_BUFFER 256
#define BUFFER_SIZE 1024
#define MAX_FRAME_SIZE (256*1024)
#define TEN_K (10*1024)
/* the boundary is used for the M-JPEG stream, it separates the multipart stream of pictures */
#define BOUNDARY "boundarydonotcross"
#define STD_HEADER "Connection: close\r\n" \
"Server: MJPG-Streamer/0.2\r\n" \
"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" \
"Pragma: no-cache\r\n" \
"Expires: Mon, 3 Jan 2000 12:34:56 GMT\r\n"
- void send_file(int id, int fd, char *parameter) {
- char buffer[BUFFER_SIZE] = {0};
- char *extension, *mimetype=NULL;
- int i, lfd;
- config conf = servers[id].conf;
- /* in case no parameter was given */
- if ( parameter == NULL || strlen(parameter) == 0 )
- parameter = "index.html";
- /* find file-extension */
- if ( (extension = strstr(parameter, ".")) == NULL ) {
- send_error(fd, 400, "No file extension found");
- return;
- }
- /* determine mime-type */
- for ( i=0; i < LENGTH_OF(mimetypes); i++ ) {
- if ( strcmp(mimetypes[i].dot_extension, extension) == 0 ) {
- mimetype = (char *)mimetypes[i].mimetype;
- break;
- }
- }
- /* in case of unknown mimetype or extension leave */
- if ( mimetype == NULL ) {
- send_error(fd, 404, "MIME-TYPE not known");
- return;
- }
- /* now filename, mimetype and extension are known */
- DBG("trying to serve file \"%s\", extension: \"%s\" mime: \"%s\"\n", parameter, extension, mimetype);
- /* build the absolute path to the file */
- strncat(buffer, conf.www_folder, sizeof(buffer)-1);
- strncat(buffer, parameter, sizeof(buffer)-strlen(buffer)-1);
- /* try to open that file */
- if ( (lfd = open(buffer, O_RDONLY)) < 0 ) {
- DBG("file %s not accessible\n", buffer);
- send_error(fd, 404, "Could not open file");
- return;
- }
- DBG("opened file: %s\n", buffer);
- /* prepare HTTP header */
- sprintf(buffer, "HTTP/1.0 200 OK\r\n" \
- "Content-type: %s\r\n" \
- STD_HEADER \
- "\r\n", mimetype);
- i = strlen(buffer);
- /* first transmit HTTP-header, afterwards transmit content of file */
- do {
- if ( write(fd, buffer, i) < 0 ) {
- close(lfd);
- return;
- }
- } while ( (i=read(lfd, buffer, sizeof(buffer))) > 0 );
- /* close file, job done */
- close(lfd);
- }
- void send_snapshot(int fd) {
- unsigned char *frame=NULL;
- int frame_size=0;
- char buffer[BUFFER_SIZE] = {0};
- /* wait for a fresh frame */
- pthread_cond_wait(&pglobal->db_update, &pglobal->db);
- /* read buffer */
- frame_size = pglobal->size;
- /* allocate a buffer for this single frame */
- if ( (frame = malloc(frame_size+1)) == NULL ) {
- free(frame);
- pthread_mutex_unlock( &pglobal->db );
- send_error(fd, 500, "not enough memory");
- return;
- }
- memcpy(frame, pglobal->buf, frame_size);
- DBG("got frame (size: %d kB)\n", frame_size/1024);
- pthread_mutex_unlock( &pglobal->db );
- /* write the response */
- sprintf(buffer, "HTTP/1.0 200 OK\r\n" \
- STD_HEADER \
- "Content-type: image/jpeg\r\n" \
- "\r\n");
- /* send header and image now */
- if( write(fd, buffer, strlen(buffer)) < 0 ) {
- free(frame);
- return;
- }
- write(fd, frame, frame_size);
- free(frame);
- }
- void send_stream(int fd) {
- unsigned char *frame=NULL, *tmp=NULL;
- int frame_size=0, max_frame_size=0;
- char buffer[BUFFER_SIZE] = {0};
- DBG("preparing header\n");
- sprintf(buffer, "HTTP/1.0 200 OK\r\n" \
- STD_HEADER \
- "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n" \
- "\r\n" \
- "--" BOUNDARY "\r\n");
- if ( write(fd, buffer, strlen(buffer)) < 0 ) {
- free(frame);
- return;
- }
- DBG("Headers send, sending stream now\n");
- while ( !pglobal->stop ) {
- /* wait for fresh frames */
- pthread_cond_wait(&pglobal->db_update, &pglobal->db);
- /* read buffer */
- frame_size = pglobal->size;
- /* check if framebuffer is large enough, increase it if necessary */
- if ( frame_size > max_frame_size ) {
- DBG("increasing buffer size to %d\n", frame_size);
- max_frame_size = frame_size+TEN_K;
- if ( (tmp = realloc(frame, max_frame_size)) == NULL ) {
- free(frame);
- pthread_mutex_unlock( &pglobal->db );
- send_error(fd, 500, "not enough memory");
- return;
- }
- frame = tmp;
- }
- memcpy(frame, pglobal->buf, frame_size);
- DBG("got frame (size: %d kB)\n", frame_size/1024);
- pthread_mutex_unlock( &pglobal->db );
- /*
- * print the individual mimetype and the length
- * sending the content-length fixes random stream disruption observed with firefox
- */
- sprintf(buffer, "Content-Type: image/jpeg\r\n" \
- "Content-Length: %d\r\n" \
- "\r\n", frame_size);
- DBG("sending intemdiate header\n");
- if ( write(fd, buffer, strlen(buffer)) < 0 ) break;
- DBG("sending frame\n");
- if( write(fd, frame, frame_size) < 0 ) break;
- DBG("sending boundary\n");
- sprintf(buffer, "\r\n--" BOUNDARY "\r\n");
- if ( write(fd, buffer, strlen(buffer)) < 0 ) break;
- }
- free(frame);
- }
- void send_error(int fd, int which, char *message) {
- char buffer[BUFFER_SIZE] = {0};
- if ( which == 401 ) {
- sprintf(buffer, "HTTP/1.0 401 Unauthorized\r\n" \
- "Content-type: text/plain\r\n" \
- STD_HEADER \
- "WWW-Authenticate: Basic realm=\"MJPG-Streamer\"\r\n" \
- "\r\n" \
- "401: Not Authenticated!\r\n" \
- "%s", message);
- } else if ( which == 404 ) {
- sprintf(buffer, "HTTP/1.0 404 Not Found\r\n" \
- "Content-type: text/plain\r\n" \
- STD_HEADER \
- "\r\n" \
- "404: Not Found!\r\n" \
- "%s", message);
- } else if ( which == 500 ) {
- sprintf(buffer, "HTTP/1.0 500 Internal Server Error\r\n" \
- "Content-type: text/plain\r\n" \
- STD_HEADER \
- "\r\n" \
- "500: Internal Server Error!\r\n" \
- "%s", message);
- } else if ( which == 400 ) {
- sprintf(buffer, "HTTP/1.0 400 Bad Request\r\n" \
- "Content-type: text/plain\r\n" \
- STD_HEADER \
- "\r\n" \
- "400: Not Found!\r\n" \
- "%s", message);
- } else {
- sprintf(buffer, "HTTP/1.0 501 Not Implemented\r\n" \
- "Content-type: text/plain\r\n" \
- STD_HEADER \
- "\r\n" \
- "501: Not Implemented!\r\n" \
- "%s", message);
- }
- write(fd, buffer, strlen(buffer));
- }
阅读(1802) | 评论(0) | 转发(0) |