Monday, July 21, 2014

Stream Video to HTML5 enabled web browser. (Windows) HLS(HTTP Live Streaming)

Here is the HTML page code for streming


<html>
<body>

<video src="http://192.168.3.155:27015/test.mp4" type="video/ogg" controls="controls" autoplay="autoplay" height="360" width="640"></video>

</body>
</html>


You can specify the src tag with only IP address and no port. But you will have to terminate the use of port 80 on your computer.

Here the c++(win32) code for stream server that will do the streaming . This is a simple code and it will not show how do multiple client connections.

#undef UNICODE

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>

// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib").

#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"

#define BUFFER_S 6000

int FileSize( const std::string& filePath )
{
const char* fpath = filePath.c_str();
FILE *fr = fopen(fpath, "rb");

if(fr != NULL)
{
fseek (fr, 0, SEEK_END);
int size = ftell (fr);
fclose (fr);

return size;
}
else
{
return -1;
}
}

int main()
{
WSADATA wsaData;
int iResult;

SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;

struct addrinfo *result = NULL;
struct addrinfo hints;

char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;

// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}

ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;

// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}

// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}

// Setup the TCP listening socket
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}

freeaddrinfo(result);

iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}

// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}

// No longer need server socket
closesocket(ListenSocket);

  struct sockaddr_in sockserv,sockclient;
  FILE* filefd;
  int count1,cnt;
  int totalcnt;


  char buff[BUFFER_S];
char buff2[BUFFER_S];

  char* ptr, strtemp[20];
  int strcnt;

std::string fileName = "d:\\test_vid\\2.mp4";
int fileSize = FileSize(fileName);

  filefd = fopen(fileName.c_str(), "rb");
  if (filefd == NULL)
  {
return 0;
  }

memset(buff, 0, sizeof(buff));

/** First data request. */
int nRet = recv(ClientSocket, // Connected client
buff, // Receive buffer
BUFSIZ, // Lenght of buffer
0); // Flags

if (nRet == INVALID_SOCKET)
{
closesocket(ListenSocket);
closesocket(ClientSocket);
return 0;
}

  buff[nRet] = '\0';
  printf("Request recieved as \n%s\n", buff);

  cnt = fread(buff2, 1, 1025, filefd);

  sprintf(buff, "HTTP/1.1 206 Partial Content\r\nContent-Type: video/ogg\r\nDate: Mon, 28 Feb 2011 10:38:19 GMT\r\nContent-Range: bytes 0-1024/%d\r\nTransfer-Encoding: chunked\r\nServer: Myserver\r\n\r\n%x\r\n", fileSize, cnt);

  count1 = strlen(buff);
  memcpy(buff + count1, buff2, cnt);
  memcpy(buff + count1 + cnt, "\r\n0\r\n\r\n", strlen("\r\n0\r\n\r\n"));

int byteToSend = count1 + cnt + strlen("\r\n0\r\n\r\n");
cnt = send(ClientSocket, buff, byteToSend, 0);
if (cnt == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}

  printf("Data sent to the client %d bytes: %s", cnt, strerror(errno));
printf("Response sent as \n%s\n", buff);
printf("\n");

  // totalcnt = 1025;
  while(1)
  {
memset(buff, 0, BUFFER_S);
int nRet = recv(ClientSocket, // Connected client
buff, // Receive buffer
BUFFER_S, // Lenght of buffer
0); // Flags

if (nRet == INVALID_SOCKET)
{
closesocket(ListenSocket);
closesocket(ClientSocket);
return 0;
}

  if(cnt <= 0)
  break;

  buff[cnt] = '\0';
  printf("Request recieved as \n%s\n", buff);
ptr = strstr(buff, "bytes=") + strlen("bytes=");

  strcnt = 0;
  while(*ptr!='-')
  {
  strtemp[strcnt] = *ptr;
  strcnt++;
  ptr++;
  }

  strtemp[strcnt] = '\0';
  //printf("strcnt = %s\n",strtemp);

  fseek(filefd, atoi(strtemp), SEEK_SET);
cnt = fread(buff2, 1, 5000, filefd);

memset(buff, 0, BUFFER_S);
  sprintf(buff, "HTTP/1.1 206 Partial Content\r\nContent-Type: video/ogg\r\nDate: Mon, 28 Feb 2011 10:38:19 GMT\r\nContent-Range: bytes %d-%d/%d\r\nTransfer-Encoding: chunked\r\nServer: Myserver\r\n\r\n%x\r\n", atoi(strtemp), atoi(strtemp) + cnt - 1, fileSize, cnt);

  count1 = strlen(buff);
  memcpy(buff + count1, buff2, cnt);
  memcpy(buff + count1 + cnt, "\r\n0\r\n\r\n", strlen("\r\n0\r\n\r\n"));

cnt = send(ClientSocket, buff, count1 + cnt + strlen("\r\n0\r\n\r\n"), 0);
if (cnt == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}

printf("Total Data sent to the client %d bytes: %s\n", cnt, strerror(errno));
printf("Response sent as \n%s\n", buff);
printf("\n");
  }

fclose(filefd);
closesocket(ListenSocket);
closesocket(ClientSocket);
  return 0;

}