blob: 837e5b63720b54f07271447a29bd74c3662bb9f9 [file] [log] [blame]
Andreas Huberafed0e12011-09-20 15:39:58 -07001/*
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(
Andreas Huberb5f25f02013-02-05 10:14:26 -080035 const sp<AMessage> &notify,
Andreas Huber1b86fe02014-01-29 11:13:26 -080036 const sp<IMediaHTTPService> &httpService,
Andreas Huberafed0e12011-09-20 15:39:58 -070037 const char *url,
38 const KeyedVector<String8, String8> *headers,
39 bool uidValid,
40 uid_t uid)
Andreas Huberb5f25f02013-02-05 10:14:26 -080041 : Source(notify),
42 mDurationUs(0ll),
Andreas Huberafed0e12011-09-20 15:39:58 -070043 mAudioIsVorbis(false) {
44 DataSource::RegisterDefaultSniffers();
45
46 sp<DataSource> dataSource =
Andreas Huber1b86fe02014-01-29 11:13:26 -080047 DataSource::CreateFromURI(httpService, url, headers);
Andreas Huberafed0e12011-09-20 15:39:58 -070048 CHECK(dataSource != NULL);
49
50 initFromDataSource(dataSource);
51}
52
53NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080054 const sp<AMessage> &notify,
Andreas Huberafed0e12011-09-20 15:39:58 -070055 int fd, int64_t offset, int64_t length)
Andreas Huberb5f25f02013-02-05 10:14:26 -080056 : Source(notify),
57 mDurationUs(0ll),
Andreas Huberafed0e12011-09-20 15:39:58 -070058 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
Andreas Huber9575c962013-02-05 13:59:56 -0800110void 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
Andreas Huberafed0e12011-09-20 15:39:58 -0700130void 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
Andreas Huber84066782011-08-16 09:34:26 -0700156sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700157 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
Andreas Huberafed0e12011-09-20 15:39:58 -0700286} // namespace android