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