Hi all,
I am trying to implement MJPEG streaming server using MHD. I have
attached my test code.
Basically I am looping through a directory with JPEG files to create
each frame. And I am able to start the process without any error.
But fetching the URL using wget gets stuck . Vlc player shows the first
frame only.
I suspect there is some issue with buffer handling in the callback
function. Please take a look and let me know if you find any issues in
my code(Please note that this is just POC code). Also If there is a
publicly available implementation of MJPEG server using MHD please let
me know.
Thanks for your time.
Regards,
Kiran G
/*
* Copyright (C) 2011-2013 Red Hat, Inc.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Author: Gris Ge <fge <at> redhat.com>
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <microhttpd.h>
#include <json/json.h>
#include <uriparser/Uri.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/param.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define PAGE "<html><head><title>File not found</title></head><body>File not found</body></html>"
#define PORT 8888
#define TMO 60000
#define LSM_SOCK_BUFF_LEN 250 // No idea why 4096 fail.
#define LSM_DEFAULT_ID 100
#define JSON_MIME "application/json"
#define LSM_HEADER_LEN 10
#define LSM_API_VER_LEN 4
// gcc lsm_rest.c -lmicrohttpd -ljson-c -luriparser -o lsm_restd
static ssize_t
callback (void *cls, uint64_t pos, char *buf, size_t max)
{
int ret;
char fullFileName[100];
char *header="--MyBoundary\r\nContent-Type: image/jpeg\r\n\r\n";
int headersize=strlen(header);
FILE *file;
char **filelist = (char *[]) {
"/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/320x240_2.jpg","/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/960x720_1.jpg","/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/960x720_2.jpg","/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/640x480_2.jpg","/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/320x240_1.jpg","/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/160x120_1.jpg","/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/640x480_1.jpg","/home/kiran/mjpg-streamer-read-only/mjpg-streamer-1.6.3/plugins/input_testpicture/pictures/160x120_2.jpg"
};
static int file_num=0;
printf("callback 1 %d \n",file_num);
sleep(5);
struct stat buf1;
printf("callback 2 file %s \n",filelist[file_num]);
printf("callback 3 \n");
if (0 == stat (filelist[file_num], &buf1))
{
printf("STAT ok\n");
file = fopen (filelist[file_num], "rb");
perror ("The following error occurred");
}
else
{
printf("STAT error\n");
file = NULL;
return 0;
}
if (file == NULL)
{
printf("callback NULL \n");
}
else
{
printf("callback 4 \n");
file_num++;
if(file_num >7)
{
file_num=0;
}
printf("callback 5 \n");
(void) fseek (file, pos, SEEK_SET);
strcpy(buf,header);
ret=fread (buf+headersize, 1, max, file);
fclose(file);
if(ret==0)
buf[0]='\0';
printf("Returning %d \n",ret);
return ret+headersize;
}
printf("HERE5\n");
}
static void
free_callback (void *cls)
{
}
int file_handler(void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
const char *arg = MHD_lookup_connection_value (connection,MHD_GET_ARGUMENT_KIND, "test");
printf ("file_handler New %s request, URL: %s ARG: %s\n", method, url,arg); // code_debug
}
int view_handler(void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
struct MHD_Response *response;
int ret;
printf("Before MHD_create_response_from_callback\n");
response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 32 * 1024, /* 32k page size */
&callback,
0,
&free_callback);
printf("After MHD_create_response_from_callback\n");
if (response == NULL)
{
return MHD_NO;
}
MHD_add_response_header(response, "Content-Type", "multipart/x-mixed-replace;boundary=MyBoundary");
MHD_add_response_header(response, "Cache-Control", "no-cache");
MHD_add_response_header(response, "Expires", "Thu, 01 Dec 1994 16:00:00 GMT");
MHD_add_response_header(response, "Connection", "close");
printf("Before MHD_queue_response\n");
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
printf("After MHD_queue_response\n");
MHD_destroy_response (response);
const char *arg = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND, "test");
printf ("view_handler New %s request, URL: %s ARG: %s\n", method, url,arg); // code_debug
}
int answer_to_connection(void *cls, struct MHD_Connection *connection,
const char *url,
const char *method, const char *version,
const char *upload_data,
size_t *upload_data_size, void **con_cls)
{
char *url_copy;
url_copy=strdup(url);
struct MHD_Response *response;
printf("HERE\n");
if (0 != strcmp (method, "GET")) {
return MHD_NO;
}
if (strlen(url) == 1) {
return MHD_NO;
}
printf("HERE\n");
//char command[10];
char *url_without_arguments = strtok(url_copy, "?");
printf("URL without arguments : %s\n",url_without_arguments);
char *command = strtok(url_without_arguments, "/");
printf("Command : %s\n",command);
//Removing arguments (?test)
if(0==strcmp(command,"file"))
{
file_handler(cls, connection,url,method, version,upload_data,upload_data_size, con_cls);
}
else if(0==strcmp(command,"view"))
{
view_handler(cls, connection,url,method, version,upload_data,upload_data_size, con_cls);
}
//MHD_destroy_response(response);
}
int main (int argc, char *argv[])
{
struct MHD_Daemon *daemon;
daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
&answer_to_connection, NULL, MHD_OPTION_END);
if (NULL == daemon) return 1;
getchar();
MHD_stop_daemon(daemon);
return 0;
}