GenericSource.cpp revision dd235727a1b4e283deeb581559f99c2c8889da07
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
32namespace android {
33
34NuPlayer::GenericSource::GenericSource(
35        const sp<AMessage> &notify,
36        const sp<IMediaHTTPService> &httpService,
37        const char *url,
38        const KeyedVector<String8, String8> *headers)
39    : Source(notify),
40      mDurationUs(0ll),
41      mAudioIsVorbis(false) {
42    DataSource::RegisterDefaultSniffers();
43
44    sp<DataSource> dataSource =
45        DataSource::CreateFromURI(httpService, url, headers);
46    CHECK(dataSource != NULL);
47
48    initFromDataSource(dataSource);
49}
50
51NuPlayer::GenericSource::GenericSource(
52        const sp<AMessage> &notify,
53        int fd, int64_t offset, int64_t length)
54    : Source(notify),
55      mDurationUs(0ll),
56      mAudioIsVorbis(false) {
57    DataSource::RegisterDefaultSniffers();
58
59    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
60
61    initFromDataSource(dataSource);
62}
63
64void NuPlayer::GenericSource::initFromDataSource(
65        const sp<DataSource> &dataSource) {
66    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
67
68    CHECK(extractor != NULL);
69
70    sp<MetaData> fileMeta = extractor->getMetaData();
71    if (fileMeta != NULL) {
72        int64_t duration;
73        if (fileMeta->findInt64(kKeyDuration, &duration)) {
74            mDurationUs = duration;
75        }
76    }
77
78    for (size_t i = 0; i < extractor->countTracks(); ++i) {
79        sp<MetaData> meta = extractor->getTrackMetaData(i);
80
81        const char *mime;
82        CHECK(meta->findCString(kKeyMIMEType, &mime));
83
84        sp<MediaSource> track = extractor->getTrack(i);
85
86        if (!strncasecmp(mime, "audio/", 6)) {
87            if (mAudioTrack.mSource == NULL) {
88                mAudioTrack.mIndex = i;
89                mAudioTrack.mSource = track;
90
91                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
92                    mAudioIsVorbis = true;
93                } else {
94                    mAudioIsVorbis = false;
95                }
96            }
97        } else if (!strncasecmp(mime, "video/", 6)) {
98            if (mVideoTrack.mSource == NULL) {
99                mVideoTrack.mIndex = i;
100                mVideoTrack.mSource = track;
101            }
102        }
103
104        if (track != NULL) {
105            mSources.push(track);
106            int64_t durationUs;
107            if (meta->findInt64(kKeyDuration, &durationUs)) {
108                if (durationUs > mDurationUs) {
109                    mDurationUs = durationUs;
110                }
111            }
112        }
113    }
114}
115
116NuPlayer::GenericSource::~GenericSource() {
117}
118
119void NuPlayer::GenericSource::prepareAsync() {
120    if (mVideoTrack.mSource != NULL) {
121        sp<MetaData> meta = mVideoTrack.mSource->getFormat();
122
123        int32_t width, height;
124        CHECK(meta->findInt32(kKeyWidth, &width));
125        CHECK(meta->findInt32(kKeyHeight, &height));
126
127        notifyVideoSizeChanged(width, height);
128    }
129
130    notifyFlagsChanged(
131            FLAG_CAN_PAUSE
132            | FLAG_CAN_SEEK_BACKWARD
133            | FLAG_CAN_SEEK_FORWARD
134            | FLAG_CAN_SEEK);
135
136    notifyPrepared();
137}
138
139void NuPlayer::GenericSource::start() {
140    ALOGI("start");
141
142    if (mAudioTrack.mSource != NULL) {
143        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
144
145        mAudioTrack.mPackets =
146            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
147
148        readBuffer(true /* audio */);
149    }
150
151    if (mVideoTrack.mSource != NULL) {
152        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
153
154        mVideoTrack.mPackets =
155            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
156
157        readBuffer(false /* audio */);
158    }
159}
160
161status_t NuPlayer::GenericSource::feedMoreTSData() {
162    return OK;
163}
164
165sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
166    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
167
168    if (source == NULL) {
169        return NULL;
170    }
171
172    return source->getFormat();
173}
174
175status_t NuPlayer::GenericSource::dequeueAccessUnit(
176        bool audio, sp<ABuffer> *accessUnit) {
177    Track *track = audio ? &mAudioTrack : &mVideoTrack;
178
179    if (track->mSource == NULL) {
180        return -EWOULDBLOCK;
181    }
182
183    status_t finalResult;
184    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
185        return finalResult == OK ? -EWOULDBLOCK : finalResult;
186    }
187
188    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
189
190    readBuffer(audio, -1ll);
191
192    return result;
193}
194
195status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
196    *durationUs = mDurationUs;
197    return OK;
198}
199
200size_t NuPlayer::GenericSource::getTrackCount() const {
201    return mSources.size();
202}
203
204sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const {
205    size_t trackCount = mSources.size();
206    if (trackIndex >= trackCount) {
207        return NULL;
208    }
209
210    sp<AMessage> format = new AMessage();
211    sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
212
213    const char *mime;
214    CHECK(meta->findCString(kKeyMIMEType, &mime));
215
216    int32_t trackType;
217    if (!strncasecmp(mime, "video/", 6)) {
218        trackType = MEDIA_TRACK_TYPE_VIDEO;
219    } else if (!strncasecmp(mime, "audio/", 6)) {
220        trackType = MEDIA_TRACK_TYPE_AUDIO;
221    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
222        trackType = MEDIA_TRACK_TYPE_TIMEDTEXT;
223    } else {
224        trackType = MEDIA_TRACK_TYPE_UNKNOWN;
225    }
226    format->setInt32("type", trackType);
227
228    const char *lang;
229    if (!meta->findCString(kKeyMediaLanguage, &lang)) {
230        lang = "und";
231    }
232    format->setString("language", lang);
233
234    if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) {
235        format->setString("mime", mime);
236
237        int32_t isAutoselect = 1, isDefault = 0, isForced = 0;
238        meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect);
239        meta->findInt32(kKeyTrackIsDefault, &isDefault);
240        meta->findInt32(kKeyTrackIsForced, &isForced);
241
242        format->setInt32("auto", !!isAutoselect);
243        format->setInt32("default", !!isDefault);
244        format->setInt32("forced", !!isForced);
245    }
246
247    return format;
248}
249
250status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
251    if (mVideoTrack.mSource != NULL) {
252        int64_t actualTimeUs;
253        readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
254
255        seekTimeUs = actualTimeUs;
256    }
257
258    if (mAudioTrack.mSource != NULL) {
259        readBuffer(true /* audio */, seekTimeUs);
260    }
261
262    return OK;
263}
264
265void NuPlayer::GenericSource::readBuffer(
266        bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
267    Track *track = audio ? &mAudioTrack : &mVideoTrack;
268    CHECK(track->mSource != NULL);
269
270    if (actualTimeUs) {
271        *actualTimeUs = seekTimeUs;
272    }
273
274    MediaSource::ReadOptions options;
275
276    bool seeking = false;
277
278    if (seekTimeUs >= 0) {
279        options.setSeekTo(seekTimeUs);
280        seeking = true;
281    }
282
283    for (;;) {
284        MediaBuffer *mbuf;
285        status_t err = track->mSource->read(&mbuf, &options);
286
287        options.clearSeekTo();
288
289        if (err == OK) {
290            size_t outLength = mbuf->range_length();
291
292            if (audio && mAudioIsVorbis) {
293                outLength += sizeof(int32_t);
294            }
295
296            sp<ABuffer> buffer = new ABuffer(outLength);
297
298            memcpy(buffer->data(),
299                   (const uint8_t *)mbuf->data() + mbuf->range_offset(),
300                   mbuf->range_length());
301
302            if (audio && mAudioIsVorbis) {
303                int32_t numPageSamples;
304                if (!mbuf->meta_data()->findInt32(
305                            kKeyValidSamples, &numPageSamples)) {
306                    numPageSamples = -1;
307                }
308
309                memcpy(buffer->data() + mbuf->range_length(),
310                       &numPageSamples,
311                       sizeof(numPageSamples));
312            }
313
314            int64_t timeUs;
315            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
316
317            buffer->meta()->setInt64("timeUs", timeUs);
318
319            if (actualTimeUs) {
320                *actualTimeUs = timeUs;
321            }
322
323            mbuf->release();
324            mbuf = NULL;
325
326            if (seeking) {
327                track->mPackets->queueDiscontinuity(
328                        ATSParser::DISCONTINUITY_SEEK,
329                        NULL,
330                        true /* discard */);
331            }
332
333            track->mPackets->queueAccessUnit(buffer);
334            break;
335        } else if (err == INFO_FORMAT_CHANGED) {
336#if 0
337            track->mPackets->queueDiscontinuity(
338                    ATSParser::DISCONTINUITY_FORMATCHANGE,
339                    NULL,
340                    false /* discard */);
341#endif
342        } else {
343            track->mPackets->signalEOS(err);
344            break;
345        }
346    }
347}
348
349}  // namespace android
350