• 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 char * url,const KeyedVector<String8,String8> * headers,bool uidValid,uid_t uid)34 NuPlayer::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 
GenericSource(int fd,int64_t offset,int64_t length)50 NuPlayer::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 
initFromDataSource(const sp<DataSource> & dataSource)61 void 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 
~GenericSource()102 NuPlayer::GenericSource::~GenericSource() {
103 }
104 
start()105 void 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 
feedMoreTSData()127 status_t NuPlayer::GenericSource::feedMoreTSData() {
128     return OK;
129 }
130 
getFormatMeta(bool audio)131 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
132     sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
133 
134     if (source == NULL) {
135         return NULL;
136     }
137 
138     return source->getFormat();
139 }
140 
dequeueAccessUnit(bool audio,sp<ABuffer> * accessUnit)141 status_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 
getDuration(int64_t * durationUs)161 status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) {
162     *durationUs = mDurationUs;
163     return OK;
164 }
165 
seekTo(int64_t seekTimeUs)166 status_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 
readBuffer(bool audio,int64_t seekTimeUs,int64_t * actualTimeUs)181 void 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 
flags() const261 uint32_t NuPlayer::GenericSource::flags() const {
262     return FLAG_SEEKABLE;
263 }
264 
265 }  // namespace android
266