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