blob: f281879b24a78203b567b725897bbe6df0102ec2 [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(
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
Andreas Huber84066782011-08-16 09:34:26 -0700131sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
Andreas Huberafed0e12011-09-20 15:39:58 -0700132 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
Andreas Huberb7c8e912012-11-27 15:02:53 -0800261uint32_t NuPlayer::GenericSource::flags() const {
262 return FLAG_SEEKABLE;
Andreas Huberafed0e12011-09-20 15:39:58 -0700263}
264
265} // namespace android