stagefright: httplive: Decouple block size from bandwidth estimate
A very small block size in PlaylistFetcher can lead to framework
overhead and difficulty streaming high bitrate content, but since
HTTPBase keeps a constant history of the past 100 HTTP reads, the
block size directly affects bandwidth estimation and in turn,
switching latency.
Add setBandwidthHistorySize() to HTTPBase to allow setting the
history size for bandwidth estimation. Call this within LiveSession
based on the current block size to ensure that the number of bytes
used for estimating bandwidth does not change if the block size is
changed in PlaylistFetcher.
Since a single TCP/IP packet can contain up to 64k of data, increase
the block size in PlaylistFetcher from 2k to lcm(188, 1024) or 47k to
avoid inaccuracies in read timings due to up to a comparable 47 reads
from the same locally-cached packet instead of from the network.
Also make HTTPBase::addBandwidthMeasurement() virtual to allow
bandwidth estimation extensions that do not rely on a history list.
Bug: 18821145
Change-Id: I5f957be01f5346e74cfb7eeb150ca4b397ad5798
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 32291c8..0c2ff15 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -36,7 +36,8 @@
mTotalTransferBytes(0),
mPrevBandwidthMeasureTimeUs(0),
mPrevEstimatedBandWidthKbps(0),
- mBandWidthCollectFreqMs(5000) {
+ mBandWidthCollectFreqMs(5000),
+ mMaxBandwidthHistoryItems(100) {
}
void HTTPBase::addBandwidthMeasurement(
@@ -50,7 +51,7 @@
mTotalTransferBytes += numBytes;
mBandwidthHistory.push_back(entry);
- if (++mNumBandwidthHistoryItems > 100) {
+ if (++mNumBandwidthHistoryItems > mMaxBandwidthHistoryItems) {
BandwidthEntry *entry = &*mBandwidthHistory.begin();
mTotalTransferTimeUs -= entry->mDelayUs;
mTotalTransferBytes -= entry->mNumBytes;
@@ -104,6 +105,10 @@
return OK;
}
+void HTTPBase::setBandwidthHistorySize(size_t numHistoryItems) {
+ mMaxBandwidthHistoryItems = numHistoryItems;
+}
+
// static
void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
int res = qtaguid_tagSocket(sockfd, kTag, uid);
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index e163985..9daab3b 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -49,6 +49,9 @@
namespace android {
+// Number of recently-read bytes to use for bandwidth estimation
+const size_t LiveSession::kBandwidthHistoryBytes = 200 * 1024;
+
LiveSession::LiveSession(
const sp<AMessage> ¬ify, uint32_t flags,
const sp<IMediaHTTPService> &httpService)
@@ -84,6 +87,13 @@
mPacketSources2.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
mBuffering[i] = false;
}
+
+ size_t numHistoryItems = kBandwidthHistoryBytes /
+ PlaylistFetcher::kDownloadBlockSize + 1;
+ if (numHistoryItems < 5) {
+ numHistoryItems = 5;
+ }
+ mHTTPDataSource->setBandwidthHistorySize(numHistoryItems);
}
LiveSession::~LiveSession() {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 896a8fc..dfb5e59 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -114,6 +114,8 @@
kWhatSwitchDown = 'sDwn',
};
+ static const size_t kBandwidthHistoryBytes;
+
struct BandwidthItem {
size_t mPlaylistIndex;
unsigned long mBandwidth;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 07c86e5..4a97803 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -49,7 +49,8 @@
// static
const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
-const int32_t PlaylistFetcher::kDownloadBlockSize = 2048;
+// LCM of 188 (size of a TS packet) & 1k works well
+const int32_t PlaylistFetcher::kDownloadBlockSize = 47 * 1024;
const int32_t PlaylistFetcher::kNumSkipFrames = 5;
PlaylistFetcher::PlaylistFetcher(
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 2788451..67161a9 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -35,6 +35,7 @@
struct PlaylistFetcher : public AHandler {
static const int64_t kMinBufferedDurationUs;
+ static const int32_t kDownloadBlockSize;
enum {
kWhatStarted,
@@ -95,7 +96,6 @@
};
static const int64_t kMaxMonitorDelayUs;
- static const int32_t kDownloadBlockSize;
static const int32_t kNumSkipFrames;
static bool bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer);
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index 1c3cd5e..0c66e27 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -48,6 +48,8 @@
virtual status_t setBandwidthStatCollectFreq(int32_t freqMs);
+ virtual void setBandwidthHistorySize(size_t numHistoryItems);
+
static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
static void UnRegisterSocketUserTag(int sockfd);
@@ -55,7 +57,7 @@
static void UnRegisterSocketUserMark(int sockfd);
protected:
- void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
+ virtual void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
private:
struct BandwidthEntry {
@@ -69,6 +71,7 @@
size_t mNumBandwidthHistoryItems;
int64_t mTotalTransferTimeUs;
size_t mTotalTransferBytes;
+ size_t mMaxBandwidthHistoryItems;
enum {
kMinBandwidthCollectFreqMs = 1000, // 1 second