• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &notify,
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> &notify,
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