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