How to push the H.264 format data received from socket to RTMP server?

南笙酒味 提交于 2021-01-29 14:14:03

问题


My test_ffmpeg.c can push the local H.264 video to the RTMP server,and received_video.c can receive h.264 format data from socket, but now I want to push the H264 format data received from the socket to the RTMP server. Excuse me, can it be implemented? and How can I modify my code?

note 1:Three methods I found on the Internet.I want to use the third one, but I don't know how to modify it.

Method 1: set up RTMP server locally, change the port number of local RTMP 
server to the same as socket monitoring, and then the local RTMP server 
will listen to the data and forward it to the remote RTMP server;

Method 2: cache the H264 monitored by socket, implement RTMP protocol by 
myself, and then push it to the remote RTMP server;

Method 3: I need  to modify ffmpeg API and set callback, that is in my 
test_ffmpeg.c can be modified.

note 2:

test_ffmpeg.c : push the local h.264 video to the rtmp server.

received_video.c : received h.264  format data from the socket.

test_ffmpeg.c

#include <stdio.h>

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"
#include "libavutil/mathematics.h"
#include "libavutil/time.h"

typedef long long int64;

int main(void)
{
    AVOutputFormat *ofmt = NULL;
    AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
    AVPacket pkt;
    const char *in_filename, *out_filename;
    int ret, i;
    int videoindex = -1;
    int frame_index = 0;
    int64 start_time = 0;
    in_filename = "./test.h264"; 

    out_filename = "rtmp://192.168.1.108/mytv/01";
#if 0    
    av_register_all();
#endif 
    avformat_network_init();

    if ((ret == avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0)
    {
        printf("Could not open input file.\n");
        goto end;
    }
    if ((ret == avformat_find_stream_info(ifmt_ctx, 0)) < 0)
    {
        printf("Failed to retrieve input stream information!\n");
        goto end;
    }

    for (i = 0; i < ifmt_ctx->nb_streams; i++)
    {
        if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoindex = i;
            break;
        }
    }
    av_dump_format(ifmt_ctx, 0, in_filename, 0);

    avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_filename);

    if (!ofmt_ctx)
    {
        printf("Could not create output context!\n");
        ret = AVERROR_UNKNOWN;
        goto end;
    }

    ofmt = ofmt_ctx->oformat;
    for (i = 0;i < ifmt_ctx->nb_streams; i++)
    {
        AVStream *in_stream = ifmt_ctx->streams[i];
        AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
//      AVStream *out_stream = avformat_new_stream(ofmt_ctx, NULL);
        if (!out_stream)
        {
            printf("Failed allocating output stream!\n");
            ret = AVERROR_UNKNOWN;
            goto end;
        }
#if 0
        ret = avcodec_copy_context(out_stream->codecpar, in_stream->codecpar);
#endif 
        ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
        if (ret < 0)
        {
            printf("Failed to copy context from input to output stream codec context!\n");
            goto end;
        }
        out_stream->codecpar->codec_tag = 0;
#if 0
        if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
        {
            out_stream->codec->flags | AV_CODEC_FLAG_GLOBAL_HEADER;
        }
#endif
    }
    av_dump_format(ofmt_ctx, 0, out_filename, 1);
#if 0
    if (!(ofmt->flags & AVFMT_NOFILE))
#endif
    {
        ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
        if (ret < 0)
        {
            printf("Could not open output URL '%s'", out_filename);
            goto end;
        }
    }
    ret = avformat_write_header(ofmt_ctx, NULL);
    if (ret < 0)
    {
        printf("Error occurred when opening output URL!\n");
    }

    start_time = av_gettime();

    while (1)
   {
        AVStream *in_stream, *out_stream;
        ret = av_read_frame(ifmt_ctx, &pkt);
        if (ret < 0)
        {
            break;
        }
        if (pkt.pts == AV_NOPTS_VALUE)
        {
            AVRational time_base1 = ifmt_ctx->streams[videoindex]->time_base;
            int64 calc_duration = (double)AV_TIME_BASE/av_q2d(ifmt_ctx->streams[videoindex]- 
   >r_frame_rate);
        
             pkt.pts = (double)(frame_index*calc_duration)/(double) 
(av_q2d(time_base1)*AV_TIME_BASE);
             pkt.dts = pkt.pts;
             pkt.duration = (double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
        }
        if (pkt.stream_index == videoindex)
        {
            AVRational time_base = ifmt_ctx->streams[videoindex]->time_base;
            AVRational time_base_q = {1, AV_TIME_BASE};
        
            int64 pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);
            int64 now_time = av_gettime() - start_time;
            if (pts_time > now_time)
            {
                av_usleep(pts_time - now_time);
            }
        }
        in_stream  = ifmt_ctx->streams[pkt.stream_index];
        out_stream = ofmt_ctx->streams[pkt.stream_index];
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (enum 
 AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (enum 
AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;
        if(pkt.stream_index == videoindex)
        {
            printf("Send %8d video frames to output URL\n",frame_index);
            frame_index++;
        }
        ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
  //        ret = av_write_frame(ofmt_ctx, &pkt);
        if (ret < 0) 
        {
            printf( "Error muxing packet\n");
            break;
        }
 //     av_free_packet(&pkt);
 #if 0
        av_packet_unref(&pkt);
        av_write_trailer(ofmt_ctx);
 #endif
    }
end: 
    avformat_close_input(&ifmt_ctx);

    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
    {
        avio_close(ofmt_ctx->pb);
    }
    avformat_free_context(ofmt_ctx);
    if (ret < 0 && ret != AVERROR_EOF)
    {
        printf( "Error occurred.\n");
        return -1;
    }

    return 0;
}

received_video.c

VOID *ReceivedVideoFunction(VOID *arg)
{
    INT32 receivedVideoSocket = -1;
    struct sockaddr_in6 receivedVideoAddr;     
    INT32 ret = 0;
    UCHAR recvBuf[RCV_BUFF_LEN];               
    struct sockaddr_in6 clientAddr;           
    socklen_t clientAddrLen;
    INT32 recvCount = -1;
    INT32 tmpLN = 0;
    INT32 tmpSD = 0;
    INT32 i = 0;
    unsigned int ii = 0;
    unsigned short lastSN = 0, dropNum = 0, currentSN = 0, lastPrintSN = 0, dorpNumfromlastprint 
= 0;
    struct timeval lastPrintTime, currentTime;
    memset(&lastPrintTime, 0, sizeof(struct timeval));
    memset(&currentTime, 0, sizeof(struct timeval));

    receivedVideoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
    if(receivedVideoSocket < 0)
    {
         printf("error : failed to create a received video socket !\n");
         exit(-1);
    }

    ForwardVideoSocket = socket(AF_INET, SOCK_DGRAM, 0);
    if(ForwardVideoSocket < 0)
    {
        printf("error : failed to create a forward video socket !\n");
        exit(-1);
    }


    memset(&receivedVideoAddr, 0, sizeof(receivedVideoAddr));
    receivedVideoAddr.sin6_family = AF_INET6;
    receivedVideoAddr.sin6_port = htons(RCV_VIDEO_PORT);
    inet_pton(AF_INET6, EC_CONTAINER_IPV6, &receivedVideoAddr.sin6_addr);
    ret = bind(receivedVideoSocket, (struct sockaddr*)&receivedVideoAddr, 
    sizeof(receivedVideoAddr));
    if(ret < 0)
    {
        printf("(%s error) failed to bind the received video socket !\n", __FUNCTION__);
        exit(-1);
    }

    while(1)
    { 
        memset(recvBuf, 0, RCV_BUFF_LEN);
        clientAddrLen = sizeof(clientAddr);
        recvCount = recvfrom(receivedVideoSocket, recvBuf, RCV_BUFF_LEN, 0, (struct 
        sockaddr*)&clientAddr, (socklen_t*)&clientAddrLen);
        if(recvCount <= 0)
        {
            //printf("test\n");
            usleep(100);
            continue;
        }
        else  
        {   
            //--------------------------------------------------------------
            //Here I want to push data to rtmp server, how to modify my code?
            //--------------------------------------------------------------
        }
    }
}

来源:https://stackoverflow.com/questions/65355580/how-to-push-the-h-264-format-data-received-from-socket-to-rtmp-server

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!