OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / media / libstagefright / httplive / LiveSource.cpp
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "LiveSource"
19 #include <utils/Log.h>
20
21 #include "include/LiveSource.h"
22 #include "include/M3UParser.h"
23 #include "include/NuHTTPDataSource.h"
24
25 #include <media/stagefright/foundation/ABuffer.h>
26 #include <media/stagefright/FileSource.h>
27 #include <media/stagefright/MediaDebug.h>
28
29 namespace android {
30
31 LiveSource::LiveSource(const char *url)
32     : mMasterURL(url),
33       mInitCheck(NO_INIT),
34       mDurationUs(-1),
35       mPlaylistIndex(0),
36       mLastFetchTimeUs(-1),
37       mSource(new NuHTTPDataSource),
38       mSourceSize(0),
39       mOffsetBias(0),
40       mSignalDiscontinuity(false),
41       mPrevBandwidthIndex(-1) {
42     if (switchToNext()) {
43         mInitCheck = OK;
44
45         determineSeekability();
46     }
47 }
48
49 LiveSource::~LiveSource() {
50 }
51
52 status_t LiveSource::initCheck() const {
53     return mInitCheck;
54 }
55
56 // static
57 int LiveSource::SortByBandwidth(const BandwidthItem *a, const BandwidthItem *b) {
58     if (a->mBandwidth < b->mBandwidth) {
59         return -1;
60     } else if (a->mBandwidth == b->mBandwidth) {
61         return 0;
62     }
63
64     return 1;
65 }
66
67 static double uniformRand() {
68     return (double)rand() / RAND_MAX;
69 }
70
71 bool LiveSource::loadPlaylist(bool fetchMaster) {
72     mSignalDiscontinuity = false;
73
74     mPlaylist.clear();
75     mPlaylistIndex = 0;
76
77     if (fetchMaster) {
78         mPrevBandwidthIndex = -1;
79
80         sp<ABuffer> buffer;
81         status_t err = fetchM3U(mMasterURL.c_str(), &buffer);
82
83         if (err != OK) {
84             return false;
85         }
86
87         mPlaylist = new M3UParser(
88                 mMasterURL.c_str(), buffer->data(), buffer->size());
89
90         if (mPlaylist->initCheck() != OK) {
91             return false;
92         }
93
94         if (mPlaylist->isVariantPlaylist()) {
95             for (size_t i = 0; i < mPlaylist->size(); ++i) {
96                 BandwidthItem item;
97
98                 sp<AMessage> meta;
99                 mPlaylist->itemAt(i, &item.mURI, &meta);
100
101                 unsigned long bandwidth;
102                 CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth));
103
104                 mBandwidthItems.push(item);
105             }
106             mPlaylist.clear();
107
108             // fall through
109             if (mBandwidthItems.size() == 0) {
110                 return false;
111             }
112
113             mBandwidthItems.sort(SortByBandwidth);
114
115             for (size_t i = 0; i < mBandwidthItems.size(); ++i) {
116                 const BandwidthItem &item = mBandwidthItems.itemAt(i);
117                 LOGV("item #%d: %s", i, item.mURI.c_str());
118             }
119         }
120     }
121
122     if (mBandwidthItems.size() > 0) {
123 #if 0
124         // Change bandwidth at random()
125         size_t index = uniformRand() * mBandwidthItems.size();
126 #elif 0
127         // There's a 50% chance to stay on the current bandwidth and
128         // a 50% chance to switch to the next higher bandwidth (wrapping around
129         // to lowest)
130         size_t index;
131         if (uniformRand() < 0.5) {
132             index = mPrevBandwidthIndex < 0 ? 0 : (size_t)mPrevBandwidthIndex;
133         } else {
134             if (mPrevBandwidthIndex < 0) {
135                 index = 0;
136             } else {
137                 index = mPrevBandwidthIndex + 1;
138                 if (index == mBandwidthItems.size()) {
139                     index = 0;
140                 }
141             }
142         }
143 #else
144         // Stay on the lowest bandwidth available.
145         size_t index = mBandwidthItems.size() - 1;  // Highest bandwidth stream
146 #endif
147
148         mURL = mBandwidthItems.editItemAt(index).mURI;
149
150         if (mPrevBandwidthIndex >= 0 && (size_t)mPrevBandwidthIndex != index) {
151             // If we switched streams because of bandwidth changes,
152             // we'll signal this discontinuity by inserting a
153             // special transport stream packet into the stream.
154             mSignalDiscontinuity = true;
155         }
156
157         mPrevBandwidthIndex = index;
158     } else {
159         mURL = mMasterURL;
160     }
161
162     if (mPlaylist == NULL) {
163         sp<ABuffer> buffer;
164         status_t err = fetchM3U(mURL.c_str(), &buffer);
165
166         if (err != OK) {
167             return false;
168         }
169
170         mPlaylist = new M3UParser(mURL.c_str(), buffer->data(), buffer->size());
171
172         if (mPlaylist->initCheck() != OK) {
173             return false;
174         }
175
176         if (mPlaylist->isVariantPlaylist()) {
177             return false;
178         }
179     }
180
181     if (!mPlaylist->meta()->findInt32(
182                 "media-sequence", &mFirstItemSequenceNumber)) {
183         mFirstItemSequenceNumber = 0;
184     }
185
186     return true;
187 }
188
189 static int64_t getNowUs() {
190     struct timeval tv;
191     gettimeofday(&tv, NULL);
192
193     return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
194 }
195
196 bool LiveSource::switchToNext() {
197     mSignalDiscontinuity = false;
198
199     mOffsetBias += mSourceSize;
200     mSourceSize = 0;
201
202     if (mLastFetchTimeUs < 0 || getNowUs() >= mLastFetchTimeUs + 15000000ll
203         || mPlaylistIndex == mPlaylist->size()) {
204         int32_t nextSequenceNumber =
205             mPlaylistIndex + mFirstItemSequenceNumber;
206
207         if (!loadPlaylist(mLastFetchTimeUs < 0)) {
208             LOGE("failed to reload playlist");
209             return false;
210         }
211
212         if (mLastFetchTimeUs < 0) {
213             mPlaylistIndex = 0;
214         } else {
215             if (nextSequenceNumber < mFirstItemSequenceNumber
216                     || nextSequenceNumber
217                             >= mFirstItemSequenceNumber + (int32_t)mPlaylist->size()) {
218                 LOGE("Cannot find sequence number %d in new playlist",
219                      nextSequenceNumber);
220
221                 return false;
222             }
223
224             mPlaylistIndex = nextSequenceNumber - mFirstItemSequenceNumber;
225         }
226
227         mLastFetchTimeUs = getNowUs();
228     }
229
230     AString uri;
231     sp<AMessage> itemMeta;
232     CHECK(mPlaylist->itemAt(mPlaylistIndex, &uri, &itemMeta));
233     LOGV("switching to %s", uri.c_str());
234
235     if (mSource->connect(uri.c_str()) != OK
236             || mSource->getSize(&mSourceSize) != OK) {
237         return false;
238     }
239
240     int32_t val;
241     if (itemMeta->findInt32("discontinuity", &val) && val != 0) {
242         mSignalDiscontinuity = true;
243     }
244
245     mPlaylistIndex++;
246     return true;
247 }
248
249 static const ssize_t kHeaderSize = 188;
250
251 ssize_t LiveSource::readAt(off_t offset, void *data, size_t size) {
252     CHECK(offset >= mOffsetBias);
253     offset -= mOffsetBias;
254
255     off_t delta = mSignalDiscontinuity ? kHeaderSize : 0;
256
257     if (offset >= mSourceSize + delta) {
258         CHECK_EQ(offset, mSourceSize + delta);
259
260         offset -= mSourceSize + delta;
261         if (!switchToNext()) {
262             return ERROR_END_OF_STREAM;
263         }
264
265         if (mSignalDiscontinuity) {
266             LOGV("switchToNext changed streams");
267         } else {
268             LOGV("switchToNext stayed within the same stream");
269         }
270
271         mOffsetBias += delta;
272
273         delta = mSignalDiscontinuity ? kHeaderSize : 0;
274     }
275
276     if (offset < delta) {
277         size_t avail = delta - offset;
278         memset(data, 0, avail);
279         return avail;
280     }
281
282     size_t numRead = 0;
283     while (numRead < size) {
284         ssize_t n = mSource->readAt(
285                 offset + numRead - delta,
286                 (uint8_t *)data + numRead, size - numRead);
287
288         if (n <= 0) {
289             break;
290         }
291
292         numRead += n;
293     }
294
295     return numRead;
296 }
297
298 status_t LiveSource::fetchM3U(const char *url, sp<ABuffer> *out) {
299     *out = NULL;
300
301     sp<DataSource> source;
302
303     if (!strncasecmp(url, "file://", 7)) {
304         source = new FileSource(url + 7);
305     } else {
306         CHECK(!strncasecmp(url, "http://", 7));
307
308         status_t err = mSource->connect(url);
309
310         if (err != OK) {
311             return err;
312         }
313
314         source = mSource;
315     }
316
317     off_t size;
318     status_t err = source->getSize(&size);
319
320     if (err != OK) {
321         size = 65536;
322     }
323
324     sp<ABuffer> buffer = new ABuffer(size);
325     buffer->setRange(0, 0);
326
327     for (;;) {
328         size_t bufferRemaining = buffer->capacity() - buffer->size();
329
330         if (bufferRemaining == 0) {
331             bufferRemaining = 32768;
332
333             LOGV("increasing download buffer to %d bytes",
334                  buffer->size() + bufferRemaining);
335
336             sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
337             memcpy(copy->data(), buffer->data(), buffer->size());
338             copy->setRange(0, buffer->size());
339
340             buffer = copy;
341         }
342
343         ssize_t n = source->readAt(
344                 buffer->size(), buffer->data() + buffer->size(),
345                 bufferRemaining);
346
347         if (n < 0) {
348             return err;
349         }
350
351         if (n == 0) {
352             break;
353         }
354
355         buffer->setRange(0, buffer->size() + (size_t)n);
356     }
357
358     *out = buffer;
359
360     return OK;
361 }
362
363 bool LiveSource::seekTo(int64_t seekTimeUs) {
364     LOGV("seek to %lld us", seekTimeUs);
365
366     if (!mPlaylist->isComplete()) {
367         return false;
368     }
369
370     int32_t targetDuration;
371     if (!mPlaylist->meta()->findInt32("target-duration", &targetDuration)) {
372         return false;
373     }
374
375     int64_t seekTimeSecs = (seekTimeUs + 500000ll) / 1000000ll;
376
377     int64_t index = seekTimeSecs / targetDuration;
378
379     if (index < 0 || index >= mPlaylist->size()) {
380         return false;
381     }
382
383     size_t newPlaylistIndex = mFirstItemSequenceNumber + index;
384
385     if (newPlaylistIndex == mPlaylistIndex) {
386         return false;
387     }
388
389     mPlaylistIndex = newPlaylistIndex;
390
391     switchToNext();
392     mOffsetBias = 0;
393
394     LOGV("seeking to index %lld", index);
395
396     return true;
397 }
398
399 bool LiveSource::getDuration(int64_t *durationUs) const {
400     if (mDurationUs >= 0) {
401         *durationUs = mDurationUs;
402         return true;
403     }
404
405     *durationUs = 0;
406     return false;
407 }
408
409 bool LiveSource::isSeekable() const {
410     return mDurationUs >= 0;
411 }
412
413 void LiveSource::determineSeekability() {
414     mDurationUs = -1;
415
416     if (!mPlaylist->isComplete()) {
417         return;
418     }
419
420     int32_t targetDuration;
421     if (!mPlaylist->meta()->findInt32("target-duration", &targetDuration)) {
422         return;
423     }
424
425     mDurationUs = targetDuration * 1000000ll * mPlaylist->size();
426 }
427
428 }  // namespace android