Search code examples
csocketsvideoffmpegudp

(C_UDP Socket Programming) How can I convert binary file to video format?


I am practicing UDP socket programming. My code's functions are below.

  1. Connect Server-Client and send "hello" message each other (it is working).
  2. Then Server is sending video file to client (problem).

Transfer video file to client is working. But it is written in binary so I can't open the video.

So I try to use ffmpeg to convert the video, but it doesn't work.

Is there something wrong in my code? How can I transfer a received file to a video file?

My environment is MacOs.

Server.c (Server Code):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>

#define PORT 8888
#define BUF_SIZE 256

int main(){
    int serv_sock;
    char message[BUF_SIZE];
    char buf[BUF_SIZE];
    int str_len;
    socklen_t clnt_adr_sz;

    struct sockaddr_in serv_adr, clnt_adr;
    
    //create socket
    serv_sock=socket(PF_INET, SOCK_DGRAM, 0);
    if(serv_sock == -1){
        perror("socket() error");
        exit(1);
    }
    
    //socket address
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family=AF_INET;
    serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
    serv_adr.sin_port=htons(PORT);
    //binding socket
    if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1){
        perror("bind() error");
        exit(1);
    }
    
    while(1){
        clnt_adr_sz=sizeof(clnt_adr);
        str_len=recvfrom(serv_sock, message, BUF_SIZE, 0, (struct sockaddr *)&clnt_adr, &clnt_adr_sz);
         if (str_len < 0) {
            perror("recvfrom error");
            exit(1);
        }
    
        char hello_message[] = "hello i am server";
        if (sendto(serv_sock, hello_message, strlen(hello_message), 0, (struct sockaddr *)&clnt_adr, clnt_adr_sz) < 0) {
            perror("sendto error");
            exit(1);
        }
        
        //print message
        message[str_len] = '\0';
        printf("client say: %s\n", message);
        
        char buf[BUF_SIZE];
        ssize_t bytes_read;
        // sending viedo file
        printf("sending video file...\n");
        size_t fsize;
    
        //video file
        FILE *file;
        char *filename = "video.mp4";
        // open video file
        file = fopen(filename, "rb");
        if (file == NULL) {
            perror("File opening failed");
            exit(EXIT_FAILURE);
        }
        //calculate video file memory
        fseek(file, 0, SEEK_END);
        fsize = ftell(file);
        fseek(file,0,SEEK_SET);
    
        size_t size = htonl(fsize);
        int nsize =0;
        
        while(nsize!=fsize){
            int fpsize = fread(buf,1, BUF_SIZE, file);
            nsize += fpsize;
            if (sendto(serv_sock, &size, sizeof(size), 0, (struct sockaddr *)&clnt_adr, clnt_adr_sz) < 0) {
                perror("sendto");
                exit(EXIT_FAILURE);    
            }
            fclose(file);
            /*
            while ((bytes_read = fread(buf, 1, BUF_SIZE, file)) > 0) {
                if (sendto(serv_sock, buf, bytes_read, 0,
                       (struct sockaddr *)&clnt_adr, clnt_adr_sz) < 0) {
                    perror("sendto");
                    exit(EXIT_FAILURE);
                }       
            }
            */
        }        
    }
    close(serv_sock);
    return 0;
}

Client.c (Client code)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>

#define BUFSIZE 256
#define PORT 8888

int main(){
    int sock;
    char message[BUFSIZE];
    int str_len;
    socklen_t adr_sz;

    struct sockaddr_in serv_addr, client_addr;   
    
    sock = socket(PF_INET, SOCK_DGRAM, 0);
    if(sock == -1){
        printf("socket() error\n");
        exit(1);
    }

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(PORT);

    char hello_message[] = "hello i am client";
    sendto(sock, hello_message, strlen(hello_message), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    adr_sz = sizeof(client_addr);
    str_len=recvfrom(sock,message,BUFSIZE,0,(struct sockaddr*)&client_addr,&adr_sz);
   
    message[str_len] = '\0';
    printf("client say: %s\n", message);
    
    /*
    char buf[BUFSIZE];
    ssize_t bytes_received;
    socklen_t serv_len = sizeof(serv_addr);
    while ((bytes_received = recvfrom(sock, buf, BUFSIZE, 0,
                                      (struct sockaddr *)&serv_addr, &serv_len)) > 0) {
        fwrite(buf, 1, bytes_received, file);
    }
    */
     
    FILE *file = fopen("received_test.mp4", "wb");

    int nbyte = BUFSIZE;
    while(nbyte>= BUFSIZE){
        nbyte = recvfrom(sock, message, BUFSIZE, 0, (struct sockaddr*)&serv_addr, &adr_sz);
        fwrite(message, sizeof(char), nbyte, file);
    }

    if (file == NULL) {
        perror("File opening failed");
        exit(EXIT_FAILURE);
    }

    fclose(file);
    close(sock);
    printf("File received successfully\n");
    
    return 0;
}

I try to convert the binary file to an .mp4 file using ffmpeg but it doesn't work:

ffmpeg -i received_test.mp4 output.mp4
ffmpeg version 7.0 Copyright (c) 2000-2024 the FFmpeg developers
  built with Apple clang version 15.0.0 (clang-1500.3.9.4)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.0 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopenvino --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      59.  8.100 / 59.  8.100
  libavcodec     61.  3.100 / 61.  3.100
  libavformat    61.  1.100 / 61.  1.100
  libavdevice    61.  1.100 / 61.  1.100
  libavfilter    10.  1.100 / 10.  1.100
  libswscale      8.  1.100 /  8.  1.100
  libswresample   5.  1.100 /  5.  1.100
  libpostproc    58.  1.100 / 58.  1.100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x12a62bdb0] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x12a62bdb0] moov atom not found
[in#0 @ 0x12b0043c0] Error opening input: Invalid data found when processing input
Error opening input file received_test.mp4.
Error opening input files: Invalid data found when processing input

Solution

  • On the server side, you are not sending the video file's bytes to the client at all (you commented out that code), you are instead sending the size variable over and over, thus your client is saving a file that is just full of buffer sizes, which is why ffmpeg can't convert the data.

    Also, your server is closing the video file after the 1st loop iteration, so subsequent loop iterations can't read from the file anymore (not that it matters since you are not doing any error handling on your file reads).