Я занимаюсь программированием сокетов UDP. Функции моего кода приведены ниже.
Передача видеофайла клиенту работает. Но оно записано в двоичном формате, поэтому я не могу открыть видео.
Поэтому я пытаюсь использовать ffmpeg для конвертации видео, но это не работает.
Что-то не так в моем коде? Как перевести полученный файл в видеофайл?
Моя среда — MacOs.
Server.c (Код сервера):
#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 (Код клиента)
#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;
}
Я пытаюсь преобразовать двоичный файл в файл .mp4 с помощью ffmpeg.
но это не работает:
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





На стороне сервера вы вообще не отправляете байты видеофайла клиенту (вы закомментировали этот код), вместо этого вы отправляете переменную size снова и снова, таким образом, ваш клиент сохраняет файл, который просто заполнен буфером. размеры, поэтому ffmpeg не может конвертировать данные.
Кроме того, ваш сервер закрывает видеофайл после первой итерации цикла, поэтому последующие итерации цикла больше не могут читать файл (не то, чтобы это имело значение, поскольку вы не выполняете никакой обработки ошибок при чтении файла).
UDP не гарантирует доставку. Поскольку вы отправляете так же быстро, как читаете данные, как только какой-либо буфер на пути заполнится и начнет отбрасывать пакеты, вы потеряете данные. Используйте TCP для гарантированной доставки и управления потоком.