GenericSource.cpp revision 9575c96b6e418914e2ffc6741ecc8d71e3968dbe
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 char *url,
37        const KeyedVector<String8, String8> *headers,
38        bool uidValid,
39        uid_t uid)
40    : Source(notify),
41      mDurationUs(0ll),
42      mAudioIsVorbis(false) {
43    DataSource::RegisterDefaultSniffers();
44
45    sp<DataSource> dataSource =
46        DataSource::CreateFromURI(url, headers);
47    CHECK(dataSource != NULL);
48
49    initFromDataSource(dataSource);
50}
51
52NuPlayer::GenericSource::GenericSource(
53        const sp<AMessage> &notify,
54        int fd, int64_t offset, int64_t length)
55    : Source(notify),
56      mDurationUs(0ll),
57      mAudioIsVorbis(false) {
58    DataSource::RegisterDefaultSniffers();
59
60    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
61
62    initFromDataSource(dataSource);
63}
64
65void NuPlayer::GenericSource::initFromDataSource(
66        const sp<DataSource> &dataSource) {
67    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
68
69    CHECK(extractor != NULL);
70
71    for (size_t i = 0; i < extractor->countTracks(); ++i) {
72        sp<MetaData> meta = extractor->getTrackMetaData(i);
73
74        const char *mime;
75        CHECK(meta->findCString(kKeyMIMEType, &mime));
76
77        sp<MediaSource> track;
78
79        if (!strncasecmp(mime, "audio/", 6)) {
80            if (mAudioTrack.mSource == NULL) {
81                mAudioTrack.mSource = track = extractor->getTrack(i);
82
83                if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
84                    mAudioIsVorbis = true;
85                } else {
86                    mAudioIsVorbis = false;
87                }
88            }
89        } else if (!strncasecmp(mime, "video/", 6)) {
90            if (mVideoTrack.mSource == NULL) {
91                mVideoTrack.mSource = track = extractor->getTrack(i);
92            }
93        }
94
95        if (track != NULL) {
96            int64_t durationUs;
97            if (meta->findInt64(kKeyDuration, &durationUs)) {
98                if (durationUs > mDurationUs) {
99                    mDurationUs = durationUs;
100                }
101            }
102        }
103    }
104}
105
106NuPlayer::GenericSource::~GenericSource() {
107}
108
109void NuPlayer::GenericSource::prepareAsync() {
110    if (mVideoTrack.mSource != NULL) {
111        sp<MetaData> meta = mVideoTrack.mSource->getFormat();
112
113        int32_t width, height;
114        CHECK(meta->findInt32(kKeyWidth, &width));
115        CHECK(meta->findInt32(kKeyHeight, &height));
116
117        notifyVideoSizeChanged(width, height);
118    }
119
120    notifyFlagsChanged(
121            FLAG_CAN_PAUSE
122            | FLAG_CAN_SEEK_BACKWARD
123            | FLAG_CAN_SEEK_FORWARD
124            | FLAG_CAN_SEEK);
125
126    notifyPrepared();
127}
128
129void NuPlayer::GenericSource::start() {
130    ALOGI("start");
131
132    if (mAudioTrack.mSource != NULL) {
133        CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK);
134
135        mAudioTrack.mPackets =
136            new AnotherPacketSource(mAudioTrack.mSource->getFormat());
137
138        readBuffer(true /* audio */);
139    }
140
141    if (mVideoTrack.mSource != NULL) {
142        CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK);
143
144        mVideoTrack.mPackets =
145            new AnotherPacketSource(mVideoTrack.mSource->getFormat());
146
147        readBuffer(false /* audio */);
148    }
149}
150
151status_t NuPlayer::GenericSource::feedMoreTSData() {
152    return OK;
153}
154
155sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
156    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
157
158    if (source == NULL) {
159        return NULL;
160    }
161
162    return source->getFormat();
163}
164
165status_t NuPlayer::GenericSource::dequeueAccessUnit(
166        bool audio, sp<ABuffer> *accessUnit) {
167    Track *track = audio ? &mAudioTrack : &mVideoTrack;
168
169    if (track->mSource == NULL) {
170        return -EWOULDBLOCK;
171    }
172
173    status_t finalResult;
174    if (!track->mPackets->hasBufferAvailable(&finalResult)) {
175        return finalResult == OK ? -EWOULDBLOCK : finalResult;
176    }
177
178    status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
179
180    readBuffer(audio, -1ll);
181
182    return result;
183}
184
185status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
186    *durationUs = mDurationUs;
187    return OK;
188}
189
190status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
191    if (mVideoTrack.mSource != NULL) {
192        int64_t actualTimeUs;
193        readBuffer(false /* audio */, seekTimeUs, &actualTimeUs);
194
195        seekTimeUs = actualTimeUs;
196    }
197
198    if (mAudioTrack.mSource != NULL) {
199        readBuffer(true /* audio */, seekTimeUs);
200    }
201
202    return OK;
203}
204
205void NuPlayer::GenericSource::readBuffer(
206        bool audio, int64_t seekTimeUs, int64_t *actualTimeUs) {
207    Track *track = audio ? &mAudioTrack : &mVideoTrack;
208    CHECK(track->mSource != NULL);
209
210    if (actualTimeUs) {
211        *actualTimeUs = seekTimeUs;
212    }
213
214    MediaSource::ReadOptions options;
215
216    bool seeking = false;
217
218    if (seekTimeUs >= 0) {
219        options.setSeekTo(seekTimeUs);
220        seeking = true;
221    }
222
223    for (;;) {
224        MediaBuffer *mbuf;
225        status_t err = track->mSource->read(&mbuf, &options);
226
227        options.clearSeekTo();
228
229        if (err == OK) {
230            size_t outLength = mbuf->range_length();
231
232            if (audio && mAudioIsVorbis) {
233                outLength += sizeof(int32_t);
234            }
235
236            sp<ABuffer> buffer = new ABuffer(outLength);
237
238            memcpy(buffer->data(),
239                   (const uint8_t *)mbuf->data() + mbuf->range_offset(),
240                   mbuf->range_length());
241
242            if (audio && mAudioIsVorbis) {
243                int32_t numPageSamples;
244                if (!mbuf->meta_data()->findInt32(
245                            kKeyValidSamples, &numPageSamples)) {
246                    numPageSamples = -1;
247                }
248
249                memcpy(buffer->data() + mbuf->range_length(),
250                       &numPageSamples,
251                       sizeof(numPageSamples));
252            }
253
254            int64_t timeUs;
255            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
256
257            buffer->meta()->setInt64("timeUs", timeUs);
258
259            if (actualTimeUs) {
260                *actualTimeUs = timeUs;
261            }
262
263            mbuf->release();
264            mbuf = NULL;
265
266            if (seeking) {
267                track->mPackets->queueDiscontinuity(
268                        ATSParser::DISCONTINUITY_SEEK, NULL);
269            }
270
271            track->mPackets->queueAccessUnit(buffer);
272            break;
273        } else if (err == INFO_FORMAT_CHANGED) {
274#if 0
275            track->mPackets->queueDiscontinuity(
276                    ATSParser::DISCONTINUITY_FORMATCHANGE, NULL);
277#endif
278        } else {
279            track->mPackets->signalEOS(err);
280            break;
281        }
282    }
283}
284
285}  // namespace android
286