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