RTMP自适应比特率算法

时间:2017-04-06 12:39:56

标签: android streaming rtmp mediacodec

我在网上搜索但是关于此的信息非常少。

我有一个实时广播应用程序,我发送编码的H264视频帧和AAC音频块,由相机和放大器产生。使用Android MediaCodec SDK的麦克风,通过RTMP堆栈。

我的直播流是720p,我的目标是2500Kbps的高品质。这显然需要非常好的网络连接,如果您使用数据计划,则意味着4G。

即使最大的连接存在问题,也会出现低峰值和拥塞,因此网络将无法保持如此沉重的流量。因为我想提供高可靠性,我想在我的应用程序中包含自动自适应比特率,以便降低图像质量,使其有利或可靠。

问题是 - 如何实现这种自动适应网络条件而不丢失帧?它甚至可能吗?我使用过像Cerevo这样的专业编码设备,但它们不会丢帧 - 但是由于网络中丢失了p帧,我的应用总是会受到一些可怕的拖累。

这就是我目前所拥有的:

private long adaptBitrate(long idleNanos, Frame frame) {
        int bytes = frame.getSize();
        long nowNanos = System.nanoTime();
        if (nowNanos - mLastNanos > 1000L * 1000 * 1000) {
            double idle = (double) idleNanos / (double) (nowNanos - mLastNanos);
            float actualBitrate = newBitrate;

            int size = mBuffer.size();
            String s = "Bitrate: " + actualBitrate / 1000
                    + " kbps In-Flight:" + bytes
                    + " idle: " + idle;
            if (size > MAX_BUF_SIZE && size > mLastSize) {
                Log.i(TAG, "adaptBitrate: Dropping bitrate");
                newBitrate = (int) ((double) actualBitrate * BITRATE_DROP_MULTIPLIER);
                if (newBitrate < MIN_BITRATE) {
                    newBitrate = MIN_BITRATE;
                }
                s += "   late => " + newBitrate;
                mRtmpHandler.requestBitrate(newBitrate);
            } else if (size <= 2 && idle > IDLE_THRESHOLD) {
                mIdleFrames++;
                if(mIdleFrames >= MIN_IDLE_FRAMES){
                    Log.i(TAG, "adaptBitrate: Raising bitrate");
                    newBitrate = (int) ((double) newBitrate * BITRATE_RAISE_MULTIPLIER);
                    if (newBitrate > MAX_BITRATE) {
                        newBitrate = MAX_BITRATE;
                    }
                    s += "   idle => " + newBitrate;
                    mRtmpHandler.requestBitrate(newBitrate);
                    mIdleFrames = 0;
                }
            }
            debugThread(Log.VERBOSE, s);
            mLastNanos = System.nanoTime();
            mLastSize = size;
            idleNanos = 0;
        }
        return idleNanos;
    }

因此,如果我的缓冲区超过阈值,我会降低比特率。如果我的应用程序花了太多时间等待一个新帧,连续几帧,那么我提高了比特率。

无论我对阈值有多么谨慎,我总是丢失重要信息,我的流会中断,直到下一个关键帧到达(2秒)。有时似乎网络可以保持一定的比特率(例如,稳定在1500kbps),但图像仍然会有一些拖动,好像一帧丢失了。在良好的网络条件下,一切都很顺利。

这些流媒体设备如何处理这些情况?它总是看起来很棒,根本没有拖动或跳过框架......

1 个答案:

答案 0 :(得分:0)

令人惊讶的是,确实没有来自广播公司方面的关于自适应比特率的在线信息。当我不得不用RTSP和两个rtp套接字来实现这样的东西时,我采用了类似的方法,创建了一个轮询类,当数据包缓冲区> $ GOOD_PCT空闲时,它会适度地增加mediacodec的比特率,当它的时候积极地将它减半。队列小于$ BAD_PCT免费,如果介于两者之间则不执行任何操作。 Partially seen here。我不确定我是否根据发布的代码全面了解您的解决方案,但您是直接调整mediacodec比特率,对吗?我腐败的唯一一次是当我从mediacodec请求同步帧时,所以如果它在你的代码中,请避免它。希望这会有所帮助。