GenericSource.cpp revision 63c0ce7ab7bd99d51414dcb4f765bc6faabf367d
1/*
2 * Copyright (C) 2012 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#include "GenericSource.h"
18
19#include "AnotherPacketSource.h"
20
21#include <media/stagefright/foundation/ABuffer.h>
22#include <media/stagefright/foundation/ADebug.h>
23#include <media/stagefright/foundation/AMessage.h>
24#include <media/stagefright/DataSource.h>
25#include <media/stagefright/FileSource.h>
26#include <media/stagefright/MediaBuffer.h>
27#include <media/stagefright/MediaDefs.h>
28#include <media/stagefright/MediaExtractor.h>
29#include <media/stagefright/MediaSource.h>
30#include <media/stagefright/MetaData.h>
31#include "../../libstagefright/include/WVMExtractor.h"
32
33namespace android {
34
35NuPlayer::GenericSource::GenericSource(
36        const sp<AMessage> &notify,
37        const sp<IMediaHTTPService> &httpService,
38        const char *url,
39        const KeyedVector<String8, String8> *headers,
40        bool isWidevine,
41        bool uidValid,
42        uid_t uid)
43    : Source(notify),
44      mDurationUs(0ll),
45      mAudioIsVorbis(false),
46      mIsWidevine(isWidevine),
47      mUIDValid(uidValid),
48      mUID(uid) {
49    DataSource::RegisterDefaultSniffers();
50
51    sp<DataSource> dataSource =
52        DataSource::CreateFromURI(httpService, url, headers);
53    CHECK(dataSource != NULL);
54
55    initFromDataSource(dataSource);
56}
57
58NuPlayer::GenericSource::GenericSource(
59        const sp<AMessage> &notify,
60        int fd, int64_t offset, int64_t length)
61    : Source(notify),
62      mDurationUs(0ll),
63      mAudioIsVorbis(false),
64      mIsWidevine(false) {
65    DataSource::RegisterDefaultSniffers();
66
67    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
68
69    initFromDataSource(dataSource);
70}
71
72void NuPlayer::GenericSource::initFromDataSource(
73        const sp<DataSource> &dataSource) {
74    sp<MediaExtractor> extractor;
75
76    if (mIsWidevine) {
77        String8 mimeType;
78        float confidence;
79        sp<AMessage> dummy;
80        bool success;
81
82        success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
83        if (!success
84                || strcasecmp(
85                    mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
86            ALOGE("unsupported widevine mime: %s", mimeType.string());
87            return;
88        }
89
90        sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource);
91        wvmExtractor->setAdaptiveStreamingMode(true);
92        if (mUIDValid) {
93            wvmExtractor->setUID(mUID);
94        }
95        extractor = wvmExtractor;
96    } else {
97        extractor = MediaExtractor::Create(dataSource);
98    }
99
100    CHECK(extractor != NULL);
101
102    sp<MetaData> fileMeta = extractor->getMetaData();
103    if (fileMeta != NULL) {
104        int64_t duration;
105        if (fileMeta->findInt64(kKeyDuration, &duration)) {
106            mDurationUs = duration;
107        }
108    }
109
110    for (size_t i = 0; i < extractor->countTracks(); ++i) {
111        sp<MetaData> meta = extractor->getTrackMetaData(i);
112
113        const char *mime;
114        CHECK(meta->findCString(kKeyMIMEType, &mime));
115
116        sp<MediaSource> track = extractor->getTrack(i);
117
118        if (!strncasecmp(mime, "audio/", 6)) {
119            if (mAudioTrack.mSource == NULL) {
120                mAudioTrack.mIndex = i;
121                mAudioTrack.mSource = track;
122
123                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
124                    mAudioIsVorbis = true;
125                } else {
126                    mAudioIsVorbis = false;
127                }
128            }
129        } else if (!strncasecmp(mime, "video/", 6)) {
130            if (mVideoTrack.mSource == NULL) {
131                mVideoTrack.mIndex = i;
132                mVideoTrack.mSource = track;
133            }
134        }
135
136        if (track != NULL) {
137            mSources.push(track);
138            int64_t durationUs;
139            if (meta->findInt64(kKeyDuration, &durationUs)) {
140                if (durationUs > mDurationUs) {
141                    mDurationUs = durationUs;
142                }
143            }
144        }
145    }
146}
147
148status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) {
149    if (mIsWidevine && !audio) {
150        return mVideoTrack.mSource->setBuffers(buffers);
151    }
152    return INVALID_OPERATION;
153}
154
155NuPlayer::GenericSource::~GenericSource() {
156}
157
158void NuPlayer::GenericSource::prepareAsync() {
159    if (mVideoTrack.mSource != NULL) {
160        sp<MetaData> meta = mVideoTrack.mSource->getFormat();
161
162        int32_t width, height;
163        CHECK(meta->findInt32(kKeyWidth, &width));
164        CHECK(meta->findInt32(kKeyHeight, &height));
165
166        notifyVideoSizeChanged(width, height);
167    }
168
169    notifyFlagsChanged(
170            (mIsWidevine ? FLAG_SECURE : 0)
171            | FLAG_CAN_PAUSE
172            | FLAG_CAN_SEEK_BACKWARD
173            | FLAG_CAN_SEEK_FORWARD
174            | FLAG_CAN_SEEK);
175
176    notifyPrepared();
177}
178
179void NuPlayer::GenericSource::start() {
180    ALOGI("start");
181
182    if (mAudioTrack.mSource != NULL) {
183        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
184
185        mAudioTrack.mPackets =
186            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
187
188        readBuffer(true /* audio */);
189    }
190
191    if (mVideoTrack.mSource != NULL) {
192        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
193
194        mVideoTrack.mPackets =
195            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
196
197        readBuffer(false /* audio */);
198    }
199}
200
201status_t NuPlayer::GenericSource::feedMoreTSData() {
202    return OK;
203}
204
205sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
206    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
207
208    if (source == NULL) {
209        return NULL;
210    }
211
212    return source->getFormat();
213}
214
215status_t NuPlayer::GenericSource::dequeueAccessUnit(
216        bool audio, sp<ABuffer> *accessUnit) {
217    Track *track = audio ? &mAudioTrack : &mVideoTrack;
218
219    if (track->mSource == NULL) {
220        return -EWOULDBLOCK;
221    }
222
223    if (mIsWidevine && !audio) {
224        // try to read a buffer as we may not have been able to the last time
225        readBuffer(audio, -1ll);
226    }
227
228    status_t finalResult;
229    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
230        return (finalResult == OK ? -EWOULDBLOCK : finalResult);
231    }
232
233    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
234
235    readBuffer(audio, -1ll);
236
237    return result;
238}
239
240status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
241    *durationUs = mDurationUs;
242    return OK;
243}
244
245size_t NuPlayer::GenericSource::getTrackCount() const {
246    return mSources.size();
247}
248
249sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
250    size_t trackCount = mSources.size();
251    if (trackIndex >= trackCount) {
252        return NULL;
253    }
254
255    sp<AMessage> format = new AMessage();
256    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
257
258    const char *mime;
259    CHECK(meta->findCString(kKeyMIMEType, &mime));
260
261    int32_t trackType;
262    if (!strncasecmp(mime, "video/", 6)) {
263        trackType = MEDIA_TRACK_TYPE_VIDEO;
264    } else if (!strncasecmp(mime, "audio/", 6)) {
265        trackType = MEDIA_TRACK_TYPE_AUDIO;
266    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
267        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
268    } else {
269        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
270    }
271    format->setInt32("type", trackType);
272
273    const char *lang;
274    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
275        lang = "und";
276    }
277    format->setString("language", lang);
278
279    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
280        format->setString("mime", mime);
281
282        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
283        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
284        meta->findInt32(kKeyTrackIsDefault, &isDefault);
285        meta->findInt32(kKeyTrackIsForced, &isForced);
286
287        format->setInt32("auto", !!isAutoselect);
288        format->setInt32("default", !!isDefault);
289        format->setInt32("forced", !!isForced);
290    }
291
292    return format;
293}
294
295status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
296    if (mVideoTrack.mSource != NULL) {
297        int64_t actualTimeUs;
298        readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
299
300        seekTimeUs = actualTimeUs;
301    }
302
303    if (mAudioTrack.mSource != NULL) {
304        readBuffer(true /* audio */, seekTimeUs);
305    }
306
307    return OK;
308}
309
310void NuPlayer::GenericSource::readBuffer(
311        bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
312    Track *track = audio ? &mAudioTrack : &mVideoTrack;
313    CHECK(track->mSource != NULL);
314
315    if (actualTimeUs) {
316        *actualTimeUs = seekTimeUs;
317    }
318
319    MediaSource::ReadOptions options;
320
321    bool seeking = false;
322
323    if (seekTimeUs >= 0) {
324        options.setSeekTo(seekTimeUs);
325        seeking = true;
326    }
327
328    if (mIsWidevine && !audio) {
329        options.setNonBlocking();
330    }
331
332    for (;;) {
333        MediaBuffer *mbuf;
334        status_t err = track->mSource->read(&mbuf, &options);
335
336        options.clearSeekTo();
337
338        if (err == OK) {
339            size_t outLength = mbuf->range_length();
340
341            if (audio && mAudioIsVorbis) {
342                outLength += sizeof(int32_t);
343            }
344
345            sp<ABuffer> buffer;
346            if (mIsWidevine && !audio) {
347                // data is already provided in the buffer
348                buffer = new ABuffer(NULL, mbuf->range_length());
349                buffer->meta()->setPointer("mediaBuffer", mbuf);
350                mbuf->add_ref();
351            } else {
352                buffer = new ABuffer(outLength);
353                memcpy(buffer->data(),
354                       (const uint8_t *)mbuf->data() + mbuf->range_offset(),
355                       mbuf->range_length());
356            }
357
358            if (audio && mAudioIsVorbis) {
359                int32_t numPageSamples;
360                if (!mbuf->meta_data()->findInt32(
361                            kKeyValidSamples, &numPageSamples)) {
362                    numPageSamples = -1;
363                }
364
365                memcpy(buffer->data() + mbuf->range_length(),
366                       &numPageSamples,
367                       sizeof(numPageSamples));
368            }
369
370            int64_t timeUs;
371            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
372
373            buffer->meta()->setInt64("timeUs", timeUs);
374
375            if (actualTimeUs) {
376                *actualTimeUs = timeUs;
377            }
378
379            mbuf->release();
380            mbuf = NULL;
381
382            if (seeking) {
383                track->mPackets->queueDiscontinuity(
384                        ATSParser::DISCONTINUITY_SEEK,
385                        NULL,
386                        true /* discard */);
387            }
388
389            track->mPackets->queueAccessUnit(buffer);
390            break;
391        } else if (err == WOULD_BLOCK) {
392            break;
393        } else if (err == INFO_FORMAT_CHANGED) {
394#if 0
395            track->mPackets->queueDiscontinuity(
396                    ATSParser::DISCONTINUITY_FORMATCHANGE,
397                    NULL,
398                    false /* discard */);
399#endif
400        } else {
401            track->mPackets->signalEOS(err);
402            break;
403        }
404    }
405}
406
407}  // namespace android
408