如何使用ffmpeg和c++将自制流发布到rtmp服务器?

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

祝大家有美好的一天!

我正在为 Windows 编写一个应用程序,它将捕获屏幕并通过 rtmp 将流发送到 Wowza 服务器(用于广播)。我的应用程序使用 ffmpeg 和 Qt。 我使用 WinApi 捕获屏幕,将缓冲区转换为 YUV444(因为它最简单)并按照文件解码_encoding.c(来自 FFmpeg 示例)中的描述对帧进行编码:

///////////////////////////
//Encoder initialization
///////////////////////////
avcodec_register_all();
codec=avcodec_find_encoder(AV_CODEC_ID_H264);
c = avcodec_alloc_context3(codec);
c->width=scr_width;
c->height=scr_height;
c->bit_rate = 400000;
int base_num=1;
int base_den=1;//for one frame per second
c->time_base= (AVRational){base_num,base_den};
c->gop_size = 10;
c->max_b_frames=1;
c->pix_fmt = AV_PIX_FMT_YUV444P;
av_opt_set(c->priv_data, "preset", "slow", 0);

frame = avcodec_alloc_frame();
frame->format = c->pix_fmt;
frame->width  = c->width;
frame->height = c->height;

for(int counter=0;counter<10;counter++)
{
///////////////////////////
//Capturing Screen
///////////////////////////
    GetCapScr(shotbuf,scr_width,scr_height);//result: shotbuf is filled by screendata from HBITMAP
///////////////////////////
//Convert buffer to YUV444 (standard formula)
//It's handmade function because of problems with prepare buffer to swscale from HBITMAP
///////////////////////////
    RGBtoYUV(shotbuf,frame->linesize,frame->data,scr_width,scr_height);//result in frame->data
///////////////////////////
//Encode Screenshot
///////////////////////////
    av_init_packet(&pkt);
    pkt.data = NULL;    // packet data will be allocated by the encoder
    pkt.size = 0;
    frame->pts = counter;
    avcodec_encode_video2(c, &pkt, frame, &got_output);
    if (got_output) 
    {
        //I think that  sending packet by rtmp  must be here!
        av_free_packet(&pkt);             

    }

}
// Get the delayed frames
for (int got_output = 1,i=0; got_output; i++)
{
    ret = avcodec_encode_video2(c, &pkt, NULL, &got_output);
    if (ret < 0)
        {
            fprintf(stderr, "Error encoding frame\n");
            exit(1);
        }
        if (got_output)
        {
        //I think that  sending packet by rtmp  must be here!
        av_free_packet(&pkt);      
        }
}

///////////////////////////
//Deinitialize encoder
///////////////////////////
avcodec_close(c);
av_free(c);
av_freep(&frame->data[0]);
avcodec_free_frame(&frame);

我需要将这段代码生成的视频流发送到RTMP服务器。 换句话说,我需要 c++/c 模拟来执行此命令:

ffmpeg -re -i "sample.h264" -f flv rtmp://sample.url.com/screen/test_stream

它很有用,但我不想将流保存到文件,我想使用 ffmpeg 库进行实时编码屏幕捕获并将编码帧发送到我自己的应用程序内的 RTMP 服务器。 请给我一个小例子,如何正确初始化 AVFormatContext 并将我编码的视频 AVPackets 发送到服务器。

谢谢。

ffmpeg h.264 rtmp libavcodec libavformat
2个回答
7
投票

我的问题可以通过使用 ffmpeg 源代码中的示例来解决。需要文件

muxing.c
。它位于 ffmpeg 源代码中的文件夹
ffmpeg\docs\examples
中。将示例流写入 rtmp 服务器或文件所需的所有源代码。我必须只了解这些来源并添加我自己的流数据而不是示例流。 可能会出现意想不到的问题,但总的来说 - 有一个解决方案。


0
投票

我也遇到过同样的问题。当我使用 FFmpeg 命令行推送 RTMP 流时,没有问题。 但是,当我使用C API推流时,rtmp服务器无法解析流并始终返回“-32”,这意味着“管道损坏”。我的代码流程如下:

mp4 -> demuxing -> AVFrame -> muxing -> flv --- RTMP ---> RTMP server

原来这个问题的核心是我没有为flv流设置单独的头文件

终于,它起作用了。 将

AV_CODEC_FLAG_GLOBAL_HEADER
设置为
AVFormatContext->flags
不起作用。这导致
AVStream->codecpar->extradata
将为 NULL。这实际上会导致管道破裂。 将
AV_CODEC_FLAG_GLOBAL_HEADER
设置为
AVCodecContext->flags
可以解决问题,但应该在打开编码器之前执行。

代码的关键如:

setting the AVCodecContext...

if (FormatContext->oformat->flags & AVFMT_GLOBALHEADER){
       AVCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}

avcodec_open2(AVCodecContext, AVCodec, NULL);

解决方案也可以在ffmpeg/doc/examples/mushing.c中找到。

总体来说,当某些输出格式需要将流头分开时,就会出现这个问题,可以通过将

AV_CODEC_FLAG_GLOBAL_HEADER
设置为
AVCodecContext->flags

来解决
© www.soinside.com 2019 - 2024. All rights reserved.