Search code examples
c++opencvvlcserversocket

Display multiple OpenCv IplImages over VLC Video Output


I'm trying to send multiple frames (previsously taken from an actual video file) via socket (C++) to then play with VLC.

I've searched a lot and didn't find a solution. Hope you can help me.

So, this is my code:

#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include <string.h>
#include <time.h>
#include <errno.h>
//#include <fstream>

#include <opencv2/core/core.hpp>        // Basic OpenCV structures (cv::Mat, Scalar)
#include <opencv2/highgui/highgui.hpp>  // OpenCV window I/O

using namespace std;

#define PORT 6666
#define GROUP "127.0.0.1"
//#define INADDR_ANY

int serversock, clientsock;
int is_data_ready = 0;
struct sockaddr_in server, client;
int bytes = 0;
int count = 0;

int addrlen = sizeof(server);
int clielen = sizeof(client);

int opt = 1;

//methods
void quit(char* msg, int retval);

void quit(char* msg, int retval)
{
    if (retval == 0) {
        fprintf(stdout, (msg == NULL ? "" : msg));
        fprintf(stdout, "\n");
    } else {
        fprintf(stderr, (msg == NULL ? "" : msg));
        fprintf(stderr, "\n");
    }

    if (clientsock) closesocket(clientsock);

    if (serversock) closesocket(serversock);

    exit(retval);
}

int main()
{
    // Initialize Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"WSAStartup failed with error: %ld\n", iResult);
        return 1;
    }

    //char *imgname; //path e nome das imagens
    int i=0;
    char filename[50];
    IplImage *img = cvLoadImage(<path\\imgname.jpg); //1ª imagem como referência
    //IplImage *img2;
    CvSize size;
    size.width = img->width;
    size.height = img->height;

    /* setup server's IP and port */
    memset(&server,0,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(6666/*PORT*/);
    server.sin_addr.s_addr = inet_addr("127.0.0.1"/*GROUP*/);
    //server.sin_addr.s_addr = INADDR_ANY;

    SOCKET serversock = socket(AF_INET, SOCK_STREAM, 0);
    //SOCKET t;
    //t = socket(AF_INET, SOCK_STREAM,NULL);

    if (serversock < 0) { // or == -1
        wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        //quit("socket() failed", 1);
    }     

    /* bind the socket */
    int b = bind(serversock, (const sockaddr*)&server, sizeof(server));
    if (b < 0) {
        wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        quit("bind() failed", 1);
    }

    /* wait for connection */
    int l = listen(serversock, 5);
    if(l < 0) {
        quit("listen() failed.", 1);
    }   

    setsockopt(serversock, SOL_SOCKET, SO_KEEPALIVE, (const char*) &opt, sizeof(int));

    while(img != NULL) 
    {
        sprintf(filename, "filter\\frame_%d.jpg", i);

        img = cvLoadImage(filename);

        if (img) {
            int imgSize = (int) &size;
            sendto(serversock, img->imageData, imgSize, 0, (const struct sockaddr*)&server, addrlen);
            if(bytes < 0) { //error
                wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
                WSACleanup();
                quit("sendto FAILED", 1);
            }

            //end socket stuff

            cout << "Image sent!" << endl;   
        }
        i++;
    } 
    cvReleaseImage(&img);
}

Ant then I open VLC and set it to receive network stream on the next address: rtp://127.0.0.1:6666.

The application ends and VLC doesn't show anything.

Thanks a lot!


Solution

  • First,

    int sendto(
      _In_  SOCKET s,
      _In_  const char *buf,
      _In_  int len,
      _In_  int flags,
      _In_  const struct sockaddr *to,
      _In_  int tolen
    );
    

    sendto third argument is « The length, in bytes, of the data pointed to by the buf parameter », not the address of some OpenCV size object. So that's not surprising if your program crashes. imgSize should be img.imageSize.

    Secondly, I really doubt that VLC is able to decode a stream composed of several raw Image data, I'm pretty sure it needs some streaming protocol around it.

    First you need to use a transport protocol as streaming protocol (HTTP, RTP, etc.). Then you need to build an actual video to stream (MJPEG, MPEG4, etc.)

    Your server could relatively easily stream MJPEG over HTTP, for any other protocol, you should use an external library.

    You should search about how implementing a video streaming server in C++, see this thread : How to get started implementing a video streaming server in c/c++?