RTSP-Client-for-Microcontroller

35 views Asked by At

I am working on getting image form ip camera. Here i am trying to get raw data only. I need to implement RTSP client library to handle all request and data from ip camera. I connected microcontroller and ip camera with same wifi. I created TCP socket and connected it with ip camera.

std::string genmsg_DESCRIBE(const std::string& url, int seq, const std::string& userAgent, const std::string& authSeq) {
    std::string msgRet = "DESCRIBE " + url + " RTSP/1.0\r\n";
    msgRet += "CSeq: " + std::to_string(seq) + "\r\n";
    msgRet += "Authorization: " + authSeq + "\r\n";
    msgRet += "User-Agent: " + userAgent + "\r\n";
    msgRet += "Accept: application/sdp\r\n";
    msgRet += "\r\n";
    return msgRet;
}
std::string genmsg_SETUP(const std::string& url, int seq, const std::string& userAgent, const std::string& authSeq) {
    std::string msgRet = "SETUP " + url + " RTSP/1.0\r\n";
    msgRet += "CSeq: " + std::to_string(seq) + "\r\n";
    msgRet += "Authorization: " + authSeq + "\r\n";
    msgRet += "User-Agent: " + userAgent + "\r\n";
    msgRet += "Blocksize: 65535\r\n";
    msgRet += "Transport: RTP/AVP/TCP;unicast\r\n";
    msgRet += "\r\n";
    return msgRet;
}
std::string genmsg_OPTIONS(const std::string& url, int seq, const std::string& userAgent, const std::string& sessionId, const std::string& authSeq) {
    std::string msgRet = "OPTIONS " + url + " RTSP/1.0\r\n";
    msgRet += "CSeq: " + std::to_string(seq) + "\r\n";
    msgRet += "User-Agent: " + userAgent + "\r\n";
    msgRet += "Session: " + sessionId + "\r\n";
    msgRet += "\r\n";
    return msgRet;
}

std::string genmsg_PLAY(const std::string& url, int seq, const std::string& userAgent, const std::string& sessionId, const std::string& authSeq) {
    std::string msgRet = "PLAY " + url + " RTSP/1.0\r\n";
    msgRet += "CSeq: " + std::to_string(seq) + "\r\n";
    msgRet += "User-Agent: " + userAgent + "\r\n";
    msgRet += "Session: " + sessionId + "\r\n";
    msgRet += "Range: npt=0.000-\r\n";
    msgRet += "\r\n";
    return msgRet;
}
std::string genmsg_TEARDOWN(const std::string& url, int seq, const std::string& userAgent, const std::string& sessionId, const std::string& authSeq) {
    std::string msgRet = "TEARDOWN " + url + " RTSP/1.0\r\n";
    msgRet += "CSeq: " + std::to_string(seq) + "\r\n";
    msgRet += "User-Agent: " + userAgent + "\r\n";
    msgRet += "Session: " + sessionId + "\r\n";
    msgRet += "\r\n";
    return msgRet;
}

Is there anything wrong with this request ?

and i am using md5 hash

std::string generateAuthString(const std::string& username, const std::string& password, const std::string& realm,
                                const std::string& method, const std::string& uri, const std::string& nonce) {
    std::string combined_str1 = username + ":" + realm + ":" + password;
    std::string combined_str2 = method + ":" + uri;

    MD5_CTX context;
    MD5Init(&context);
    MD5Update(&context, reinterpret_cast<unsigned char*>(const_cast<char*>(combined_str1.c_str())), combined_str1.length());
    unsigned char m1[MD5_DIGEST_LENGTH];
    MD5Final(&context, m1);

    MD5Init(&context);
    MD5Update(&context, reinterpret_cast<unsigned char*>(const_cast<char*>(combined_str2.c_str())), combined_str2.length());
    unsigned char m2[MD5_DIGEST_LENGTH];
    MD5Final(&context, m2);

    std::string combined_str3 = bin2hex(m1, MD5_DIGEST_LENGTH) + ":" + nonce + ":" + bin2hex(m2, MD5_DIGEST_LENGTH);

    MD5Init(&context);
    MD5Update(&context, reinterpret_cast<unsigned char*>(const_cast<char*>(combined_str3.c_str())), combined_str3.length());
    unsigned char response[MD5_DIGEST_LENGTH];
    MD5Final(&context, response);

    std::stringstream mapRetInf;
    mapRetInf << "Digest ";
    mapRetInf << "username=\"" << defaultUsername << "\", ";
    mapRetInf << "realm=\"" << realm << "\", ";
    mapRetInf << "algorithm=\"MD5\", ";
    mapRetInf << "nonce=\"" << nonce << "\", ";
    mapRetInf << "uri=\"" << uri << "\", ";
    mapRetInf << "response=\"" << bin2hex(response, MD5_DIGEST_LENGTH) << "\"";

    return mapRetInf.str();
}

Since microcontroller don't have enough space and ram to handle high ram rom function so i have tried to creat simple request.

void setup() {
  const char *ssid = "Embedded";           // Put your SSID here
  const char *password = "embedded@123"; // Put your PASSWORD here
  Serial.begin(115200);
  // Connect the WiFi
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(500);
        Serial.print(".");
    
    }

    // Print information how to contact the camera server
    IPAddress ip = WiFi.localIP();
    Serial.print("\nWiFi connected with (ESP)IP:");
    Serial.println(ip);
  int seq = 1;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in serverAddress;
    // Configure server address structure
    memset(&serverAddress, 0, sizeof(serverAddress));
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_port = htons(defaultServerPort);
    inet_pton(AF_INET, defaultServerIp.c_str(), &serverAddress.sin_addr);

    
    if (connect(sockfd, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) == 0) {
            Serial.println("sync connect success");

        } else if (errno == EINPROGRESS){
            Serial.println("async connecting...");        
    }
        else {
            Serial.println("invalid connect");
            return;
        }
    std::string url = "rtsp://" + defaultServerIp + defaultTestUri;
    char buffer[BUF_LEN];
    bool isDigest = false;
    std::string authSeq = "Basic " + std::string("YWRtaW46RW1iZWRkZWRA");

    std::string mesg=genmsg_DESCRIBE(url, seq, defaultUserAgent, authSeq);
    send(sockfd, mesg.c_str(), mesg.length(), 0);
    char buffer1[BUF_LEN];
    
    ssize_t bytesRead1=recv(sockfd, buffer1, BUF_LEN, 0);
    buffer1[bytesRead1] = '\0';
    Serial.printf("%s",buffer1);
    seq++;
    mesg="";

    char* unauthorizedCheck = strstr(buffer, "Unauthorized");

    if (unauthorizedCheck) {
        isDigest = true;

        // New DESCRIBE with digest authentication
        char* start = strstr(buffer, "realm");
        char* begin = strchr(start, '\"');
        char* end = strchr(begin + 1, '\"');
        std::string realm(begin + 1, end);

        start = strstr(buffer, "nonce");
        begin = strchr(start, '\"');
        end = strchr(begin + 1, '\"');
        std::string nonce(begin + 1, end);

        authSeq = generateAuthString(defaultUsername, defaultPassword, realm, "DESCRIBE", defaultTestUri, nonce);

        mesg=genmsg_DESCRIBE(url, seq, defaultUserAgent, authSeq);
        send(sockfd, mesg.c_str(), mesg.length(), 0);
        char buffer2[BUF_LEN];
        ssize_t bytesRead2=recv(sockfd, buffer2, BUF_LEN, 0);
        buffer2[bytesRead2] = '\0';
        Serial.printf("%s",buffer2);
        seq++;
        mesg="";
    }

    control = decodeControl(buffer);

    if (isDigest) {
        authSeq = generateAuthString(defaultUsername, defaultPassword, realm, "SETUP", defaultTestUri, nonce);
    }


    

    mesg=genmsg_SETUP(control, seq, defaultUserAgent, authSeq);
    send(sockfd, mesg.c_str(), mesg.length(), 0);
    char sessionIdBuffer[BUF_LEN];
    
    ssize_t bytesRead3=recv(sockfd, sessionIdBuffer, BUF_LEN, 0);
    sessionIdBuffer[bytesRead3] = '\0';
    Serial.printf("%s",sessionIdBuffer);
    sessionId = decodeSession(sessionIdBuffer);
    seq++;
    mesg="";


    mesg=genmsg_OPTIONS(url, seq, defaultUserAgent, sessionId, authSeq);
    send(sockfd, mesg.c_str(), mesg.length(), 0);
    char optionsBuffer[BUF_LEN];
    ssize_t bytesRead4=recv(sockfd, optionsBuffer, BUF_LEN, 0);
    optionsBuffer[bytesRead4] = '\0';
    Serial.printf("%s",optionsBuffer);
    mesg="";
    seq++;


    mesg=genmsg_PLAY(url + "/", seq, defaultUserAgent, sessionId, authSeq);
    send(sockfd, mesg.c_str(), mesg.length(), 0);
    char playBuffer[BUF_LEN];
    ssize_t bytesRead5=recv(sockfd, playBuffer, BUF_LEN, 0);
    playBuffer[bytesRead5] = '\0';
    Serial.printf("%s",playBuffer);
    mesg="";
    seq++;

    starttime = time(nullptr);

    while (true) {
        // Send a new RTSP OPTION command to keep the stream alive
        time_t now = time(nullptr);
        if (difftime(now, starttime) > 50) {
            sendAndReceive(genmsg_OPTIONS(url, seq, defaultUserAgent, sessionId, authSeq), seq, sockfd);
            starttime = time(nullptr);
        }

        char msgRcvBuffer[BUF_LEN];
        //recv(sockfd, msgRcvBuffer, BUF_LEN, 0);
        Serial.printf("%s",buffer);
    }

    seq++;

    sendAndReceive(genmsg_TEARDOWN(url, seq, defaultUserAgent, sessionId, authSeq), seq, sockfd);

    char teardownBuffer[BUF_LEN];
    close(sockfd);

}

void loop() {
    

}

I am not getting data from ip camera, can you help me to understand it?

Basical everything is working and i sent play request to ip camera and got response too but i want raw data from ip camera like h264 data.

0

There are 0 answers