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;

}

Thursday, June 26, 2014

Interpolate Between Two angles(SLerp) C++ example.

This example Will show you how to interpolate between two angles that is given in degrees in 2D world. This code can be modified to use to interpolate between two 2DVectors.

In here vector3D is not included. you should write a simple vector3d class.


#include <math.h>

float PI = 3.141592653589793;

float RadianToDegree = 180.0f/PI;
float DegreeToRadian = PI/180.0f;

const float Dot(const vector3D& from, const vector3D& to)
{
return ((from.getX() * to.getX()) + (from.getZ() * to.getZ()));
}

const float Length(const vector3D& vector)
{
return sqrt((vector.getX() * vector.getX()) + (vector.getZ() * vector.getZ()));
}

vector3D Slerp(const vector3D& from, const vector3D& to, const float step)
{
if (step == 0) return from;
if (from == to || step == 1.0f) return to;

float theta = acos(Dot(from, to)/(Length(from) * Length(to)));
//float thetaDegree = theta * RadianToDegree;

if (theta == 0) return to;

float sinTheta = sin(theta);
return (from * (sin((1 - step) * theta) / sinTheta)) + (to * (sin(step * theta) / sinTheta));
}

float CurveAngle2(float from, float to, const float step)
{
if (step == 0) return from;
if (from == to || step == 1.0f)
{
return to;
}

if (from == 0.0f)
{
from = 1.0f * DegreeToRadian;
}

if (to == 0.0f)
{
to = 1.0f * DegreeToRadian;
}

VBS2Fusion::vector3D fromVector(cos(from), sin(from), 0.0f);
VBS2Fusion::vector3D toVector(cos(to), sin(to), 0.0f);

VBS2Fusion::vector3D currentVector = Slerp(fromVector, toVector, step);
float angleRadian = atan2(currentVector.getZ(), currentVector.getX());
if (angleRadian < 0.0f)
{
angleRadian = 2 * PI + angleRadian;
}

return angleRadian;
}

Saturday, June 21, 2014

RPC 1723 error can be occur when the RPC server you registered is stuck in a RPC function that the client is calling. If the 1723 error occurs check all the function that the RPC client calling is ended in the last time you have used the same server. We can check this by monitoring the RPC server listen thread(the thread that  you call RpcServerListen function) returned successfully after calling RpcMgmtStopServerListening call

Note : Even if you set DontWait = FALSE in RpcServerListen function RPC server might be stuck in the last call that it had.

Saturday, November 5, 2011

Windows RPC on C++

RPC is a famous technique for IPC(Inter-process Communication).I think u all know about RPC and how its basically works.And that is why u r here reading this blog.So without further talking about RPC lets see how we can use Microsoft Remote Procedure Call (RPC) can be used to develop application.

Microsoft Remote Procedure Call (RPC) is a integral service of most windows operating systems(Have tested on Windows XP SP2 and later versions). If u can see the windows services there two process called RpcSs and RpcLocater is running. Those are the two RPC processes that is ships with windows. If there are not there and RpcSsis not running there is a problem with ur RPC service.

What do u needed to run RPC program on ur computer?

None.It all comes with windows

What do u need to develop a application using RPC?

C/C++ compiler for windows(I used the VC90 that ships with Visual Studio 2008)
Microsoft Windows SDK.
-Version 6.0A is Ships with Visual Studio 2008.(Do not have examples)
-Microsoft Windows SDK for Windows 7 and .NET Framework 4 can be download here with all the examples.

Basic RPC example is in the directory is.\Examples\netd\rpc\hello

It uses a make file to compile and that make file is doing all the thing for u like generating C interfaces(header file with all the methods) ,client and server stubs ,compiling and linking.
It will take u some time to figure out the make file and manually convert them to visual studio project.

In this topic I will show u how to run the same example code with visual studio and some common problems I have encountered while developing a RPC application and solutions for them.

How to configure Visual Studio project

  • set additional include path as \includes
  • set linker additional directory path as \libs
  • .lib files to use by the linker -

MIDL compiler for generating stubs.

MIDL compiler is used to generate client and server stubs like in normal RPC model. 3 files are generated
-Client stub
-Server stub
-Header file(.h) for the interface
Header file has included in both client and server side code. In Client side user has to call the functions defined in the header file and it will call the client stub.In server side you have to make implementations for the .h header that u have included in C file (or cpp) and server will automatically call the implementations u provided in above .c (.cpp) file. Don`t worry about how the RPC service in windows call ur code. U will understand it eventually.


midl /Os /win32 /robust -oldnames -cpp_cmd cl -cpp_opt "-E" hello.idl

/Os --- is used for returning complex types in functions. U can use /Oi for returning complex structures like C struct.

/win32 --- Use to tell the midl compiler to build stubs for win32 system architectures.

/robust --- Is used to make run-time checks on the data that is passing in between the stubs.
This will make stubs to complain about the bad data received at the stubs.(EC 1783)


Compiler options to make build for target version of windows

Ex- For windows XP build 501
-D_WIN32_WINNT=0x0501 -DNTDDI_VERSION=0x05010000 -DWINVER=0x0501
for more