我将如何使用UDP在网络上正确发送x264编码的帧?

问题描述 投票:0回答:1

我正在尝试通过网络发送我拥有的已编码h264帧,目前,我仅在流式传输每个帧时获得的最终单位,这是正确的方法吗?

我在另一台计算机上编写了一个接收器应用程序来获取这些信号,然后将它们全部依次写入一个文件,当使用vlc播放时,我没有任何视频,而只是发出刺耳的声音。我不确定问题出在哪里。我已将FFmpeg -I命令的结果包含在创建的文件中。

编码器和发送者代码


    //Udp initialisation
    struct sockaddr_in broadcastAddr;
    int sock;
    int yes = 1;
    int addr_len;
    int count;
    fd_set readfd;
    char buffer[1024];
    int i;

    sock = socket(AF_INET, SOCK_DGRAM,0);

    if(sock < 0){
        std::cout << "Failed to initialise socket!" << std::endl;
    }

    int ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
    if(ret < 0){
        std::cout << "setsockopt error!" <<std::endl;
    }

    addr_len = sizeof(struct sockaddr_in); // the size of the address

    memset((void*)&broadcastAddr,0,addr_len); //0 out the address bits

    broadcastAddr.sin_family = AF_INET;
    broadcastAddr.sin_addr.s_addr = INADDR_BROADCAST;
    broadcastAddr.sin_port = PORT;



    //Set the encoder parameters
    x264_param_t param;
    x264_param_default_preset(&param,"veryfast","zerolatency");
    param.i_threads = 1;
    param.i_width = camera.getWidth();
    param.i_height = camera.getHeight();
    param.i_fps_num = 30;
    param.i_fps_den = 1;
// Intra refres:
    param.i_keyint_max = 30;
    param.b_intra_refresh = 1;
//Rate control:
    param.rc.i_rc_method = X264_RC_CRF;
    param.rc.f_rf_constant = 25;
    param.rc.f_rf_constant_max = 35;
//For streaming:
    param.b_repeat_headers = 1;
    param.b_annexb = 1;
    x264_param_apply_profile(&param, "baseline");

    x264_t *encoder = x264_encoder_open(&param); //H.264 encoder object
    x264_picture_t pic_in, pic_out;
    x264_picture_alloc(&pic_in, X264_CSP_I420,camera.getWidth(), camera.getHeight());

    //Network abstraction layer units for broadcast
    x264_nal_t *nals;
    int i_nals;

    while(true){

        //If there is valid data in the processing queue
        if(!encoderQueue.empty()){

            //File the x264 input data structure with the file data
            fillImage(encoderQueue.front(),camera.getWidth(),camera.getHeight(),&pic_in);

            //Encode and send
            int frame_size = x264_encoder_encode(encoder, &nals, &i_nals, &pic_in, &pic_out);
            if (frame_size >= 0) {
                //The frame is ready to be sent over UDP!
                for(int i = 0; i < i_nals; i++){
                    ret = sendto(sock, &nals[0].p_payload, frame_size,0,(struct sockaddr*)&broadcastAddr,addr_len);
                    if(ret > 0){
                        std::cout << "Streamed frame nal unit " << i  << std::endl;
                    } else{
                        std::cout << "Failed to stream nal unit " << i << std::endl;
                    }
                }
            }
            else{
                std::cout<<"Failed to encode h264 frame!" << std::endl;
            }
            //Finsihed with the current frame, pop it off the queue and remove any nals to do with it
            encoderQueue.pop();
            frame_size = 0;
            nals = nullptr;
            i_nals = 0;
        }


    }

接收器应用程序

#include <iostream>
#include <x264.h>
#include <Network/Network.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <queue>


#define BUFFER_LEN 10000
#define PORT_NO 3879



int main(int argc, const char * argv[]) {


    FILE *file; //File to write the h264 nals too

    //Declare the address memory space
    struct sockaddr_in sockAddr , bcAddr;
    socklen_t bcAddr_len = sizeof(&bcAddr); //Store the length of the broadcast address structure
    //0 out the assigned memory
    memset(&sockAddr, 0, sizeof(sockAddr));
    memset(&bcAddr, 0 ,sizeof(bcAddr));

    //Set the address parameters to look for incoming IpV4/UDP data
    sockAddr.sin_family = AF_INET;
    sockAddr.sin_port = htons(PORT_NO);
    sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    bcAddr.sin_family = AF_INET;
    bcAddr.sin_port = PORT_NO;
    inet_aton("255.255.255.255",&bcAddr.sin_addr);

    //Initialise a udp socket to read broadcast bytes
    int soc = socket(AF_INET, SOCK_DGRAM,0);

    //Check socket init
    if(soc < 0){
        std::cout << "Failed to initialise UDP socket!" << std::endl;
        return -1;
    }

    //Bind the address details to the socket, check for errors
    if(bind(soc, (struct sockaddr*)&sockAddr, sizeof(sockAddr)) < 0){
        std::cout << "Failed to bind address structure to socket!" << std::endl;
        return -2;
    }

    file = fopen("stream.h264","wb"); // Open the file for writing

    unsigned char buffer[BUFFER_LEN];

    while(true){


        memset(&buffer, 0, sizeof(unsigned char) * BUFFER_LEN);

        int recv_len = recvfrom(soc, buffer, BUFFER_LEN, 0, (struct sockaddr *)&bcAddr, &bcAddr_len);

        std::cout<< "Received " << recv_len << "bytes on broadcast address" << std::endl;

        fwrite(&buffer, sizeof(unsigned char), recv_len, file);
    }

    return 0;
}

FFMPEG -I输出

FFMPEG -I output

任何帮助将不胜感激。

c++ udp video-streaming x264 libx264
1个回答
0
投票

只要接收方和发送方都同意协议,就没有“正确”或“不正确”的方法。在此示例中,VLC正在寻找某种容器或格式。最常见的是传输流。

如果您打算读取h264流并将其写入磁盘,或将其通过管道传输到需要附件b流的地方。你在做什么是正确的。如果您希望普通玩家直接读取流,请使用传输流。

© www.soinside.com 2019 - 2024. All rights reserved.