2017-02-14 87 views
0

我正在开发一个应用程序,需要将媒体流发布到rtmp“摄取”网址(如YouTube Live中使用的,或作为Wowza Streaming Engine的输入等),我正在使用ffmpeg库(以编程方式,从C/C++,而不是命令行工具)来处理rtmp图层。我已经准备好了一个工作版本,但是在将更高带宽的数据流传输到ping服务器较差的服务器时,我发现有些问题。当使用ffmpeg“本地”/内置rtmp实现和librtmp实现时,存在这个问题。使用ffmpeg进行流发布rtmp:网络带宽未得到充分利用

当通过一个良好的网络(特别是本地Wowza服务器)流式传输到本地目标服务器时,我的代码到目前为止已经处理了我所投射的每一个流,并设法实时上传所有内容 - 这很重要,因为这是专门用于直播的。

但是,当流式传输到具有较差ping的远程服务器时(例如youtube在a.rtmp.youtube.com上发送URL,对于我来说有50 + ms ping),较低的带宽流可以正常工作,但更高带宽流的网络未充分利用 - 例如,对于400kB/s的流,我只看到〜140kB/s的网络使用率,并且很多帧会延迟/丢弃,这取决于我用来处理网络的策略推回。

现在,我知道这不是与目标服务器的网络连接问题,因为我可以在使用ffmpeg命令行工具到同一目标服务器或使用我的代码进行流式处理时实时成功上载流到当地的Wowza服务器,然后将该流转发到YouTube的摄取点。

所以网络连接不是问题,这个问题似乎与我的代码一样。

我计时我的代码各部分,发现问题出现时,调用av_write_frame/av_interleaved_write_frame(我从来不混&配合他们,我总是在任何特定的构建使用一个版本的一致,这只是我已经试验了两者,看看是否有任何区别)有时需要很长时间 - 我看到这些电话有时需要长达500-1000毫秒,但平均“坏情况”在50-100毫秒范围内。并非所有的通话都需要这么长时间,大部分时间会立即返回,但这些通话所花的平均时间会比平均持续时间长,所以我没有再实时上传。

在我看来,主要的嫌疑人可能是rtmp确认窗口机制,在发送每个N字节之后,数据发送方在发送更多数据之前等待接收确认 - 这将解释可用网络带宽没有得到充分利用,因为客户端只需坐在那里等待响应(由于较低的ping需要较长的时间),而不是使用可用带宽。虽然我没有看过ffmpeg的rtmp/librtmp代码,看它是否实际实现了这种限制,所以它可能完全是其他的东西。

的应用程序的完整代码太多,张贴在这里,但这里有一些重要的片段:

格式上下文创建:

const int nAVFormatContextCreateError = avformat_alloc_output_context2(&m_pAVFormatContext, nullptr, "flv", m_sOutputUrl.c_str()); 

流创建:

m_pVideoAVStream = avformat_new_stream(m_pAVFormatContext, nullptr); 
m_pVideoAVStream->id = m_pAVFormatContext->nb_streams - 1; 

m_pAudioAVStream = avformat_new_stream(m_pAVFormatContext, nullptr); 
m_pAudioAVStream->id = m_pAVFormatContext->nb_streams - 1; 

视频流设置:

m_pVideoAVStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 
m_pVideoAVStream->codecpar->codec_id = AV_CODEC_ID_H264; 
m_pVideoAVStream->codecpar->width = nWidth; 
m_pVideoAVStream->codecpar->height = nHeight; 
m_pVideoAVStream->codecpar->format = AV_PIX_FMT_YUV420P; 
m_pVideoAVStream->codecpar->bit_rate = 10 * 1000 * 1000; 
m_pVideoAVStream->time_base = AVRational { 1, 1000 }; 

m_pVideoAVStream->codecpar->extradata_size = int(nTotalSizeRequired); 
m_pVideoAVStream->codecpar->extradata = (uint8_t*)av_malloc(m_pVideoAVStream->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); 
// Fill in the extradata here - I'm sure I'm doing that correctly. 

音频数据流设置:

m_pAudioAVStream->time_base = AVRational { 1, 1000 }; 
// Let's leave creation of m_pAudioCodecContext out of the scope of this question, I'm quite sure everything is done right there. 
const int nAudioCodecCopyParamsError = avcodec_parameters_from_context(m_pAudioAVStream->codecpar, m_pAudioCodecContext); 

打开连接:

const int nAVioOpenError = avio_open2(&m_pAVFormatContext->pb, m_sOutputUrl.c_str(), AVIO_FLAG_WRITE); 

启动流:

AVDictionary * pOptions = nullptr; 
const int nWriteHeaderError = avformat_write_header(m_pAVFormatContext, &pOptions); 

发送视频帧:

AVPacket pkt = { 0 }; 
av_init_packet(&pkt); 
pkt.dts = nTimestamp; 
pkt.pts = nTimestamp; 
pkt.duration = nDuration; // I know what I have the wrong duration sometimes, but I don't think that's the issue. 
pkt.data = pFrameData; 
pkt.size = pFrameDataSize; 
pkt.flags = bKeyframe ? AV_PKT_FLAG_KEY : 0; 
pkt.stream_index = m_pVideoAVStream->index; 
const int nWriteFrameError = av_write_frame(m_pAVFormatContext, &pkt); // This is where too much time is spent. 

森ding an audio frame:

AVPacket pkt = { 0 }; 
av_init_packet(&pkt); 
pkt.pts = m_nTimestampMs; 
pkt.dts = m_nTimestampMs; 
pkt.duration = m_nDurationMs; 
pkt.stream_index = m_pAudioAVStream->index; 
const int nWriteFrameError = av_write_frame(m_pAVFormatContext, &pkt); 

任何想法?我是否在正确的轨道上思考确认窗口?我在做其他事情完全错误吗?

回答

0

我不认为这说明了一切,但是,为了以防万一,有人在类似的情况,修复/解决方法,我发现是:

1)ffmpeg的建立与实施librtmp RTMP协议的

2)建立与--enable-网络的ffmpeg,它增加了几个特征的librtmp协议

3)通过“rtmp_buffer_size”参数来avio_open2,并增加它的值,以一个令人满意的一个

我不能gi让你完全一步一步地解释发生了什么问题,但这至少解决了引起我问题的症状。