blob: cc0cb0155677586bc9d576c8e051d8543505de2b [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,
Andreas Huber81e68442014-02-05 11:52:33 -080038 const KeyedVector<String8, String8> *headers)
Andreas Huberb5f25f02013-02-05 10:14:26 -080039 : Source(notify),
40 mDurationUs(0ll),
Andreas Huberafed0e12011-09-20 15:39:58 -070041 mAudioIsVorbis(false) {
42 DataSource::RegisterDefaultSniffers();
43
44 sp<DataSource> dataSource =
Andreas Huber1b86fe02014-01-29 11:13:26 -080045 DataSource::CreateFromURI(httpService, url, headers);
Andreas Huberafed0e12011-09-20 15:39:58 -070046 CHECK(dataSource != NULL);
47
48 initFromDataSource(dataSource);
49}
50
51NuPlayer::GenericSource::GenericSource(
Andreas Huberb5f25f02013-02-05 10:14:26 -080052 const sp<AMessage> &notify,
Andreas Huberafed0e12011-09-20 15:39:58 -070053 int fd, int64_t offset, int64_t length)
Andreas Huberb5f25f02013-02-05 10:14:26 -080054 : Source(notify),
55 mDurationUs(0ll),
Andreas Huberafed0e12011-09-20 15:39:58 -070056 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
Marco Nelissenc1f4b2b2014-06-17 14:48:32 -070070 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
Andreas Huberafed0e12011-09-20 15:39:58 -070078 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
Robert Shihdd235722014-06-12 14:49:23 -070084 sp<MediaSource> track = extractor->getTrack(i);
Andreas Huberafed0e12011-09-20 15:39:58 -070085
86 if (!strncasecmp(mime, "audio/", 6)) {
87 if (mAudioTrack.mSource == NULL) {
Robert Shihdd235722014-06-12 14:49:23 -070088 mAudioTrack.mIndex = i;
89 mAudioTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -070090
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) {
Robert Shihdd235722014-06-12 14:49:23 -070099 mVideoTrack.mIndex = i;
100 mVideoTrack.mSource = track;
Andreas Huberafed0e12011-09-20 15:39:58 -0700101 }
102 }
103
104 if (track != NULL) {
Robert Shihdd235722014-06-12 14:49:23 -0700105 mSources.push(track);
Andreas Huberafed0e12011-09-20 15:39:58 -0700106 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
Andreas Huber9575c962013-02-05 13:59:56 -0800119void 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
Andreas Huberafed0e12011-09-20 15:39:58 -0700139void 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
Andreas Huber84066782011-08-16 09:34:26 -0700165sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700166 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
Robert Shihdd235722014-06-12 14:49:23 -0700200size_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
Andreas Huberafed0e12011-09-20 15:39:58 -0700250status_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(
Chong Zhang632740c2014-06-26 13:03:47 -0700328 ATSParser::DISCONTINUITY_SEEK,
329 NULL,
330 true /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700331 }
332
333 track->mPackets->queueAccessUnit(buffer);
334 break;
335 } else if (err == INFO_FORMAT_CHANGED) {
336#if 0
337 track->mPackets->queueDiscontinuity(
Chong Zhang632740c2014-06-26 13:03:47 -0700338 ATSParser::DISCONTINUITY_FORMATCHANGE,
339 NULL,
340 false /* discard */);
Andreas Huberafed0e12011-09-20 15:39:58 -0700341#endif
342 } else {
343 track->mPackets->signalEOS(err);
344 break;
345 }
346 }
347}
348
Andreas Huberafed0e12011-09-20 15:39:58 -0700349} // namespace android