DataSource.cpp revision faf4efc6a41e88adf85f76f48f020a6d681f5ff1
1/*
2 * Copyright (C) 2009 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//#define LOG_NDEBUG 0
17#define LOG_TAG "DataSource"
18
19#include "include/AMRExtractor.h"
20
21#include "include/AACExtractor.h"
22#include "include/DRMExtractor.h"
23#include "include/FLACExtractor.h"
24#include "include/HTTPBase.h"
25#include "include/MidiExtractor.h"
26#include "include/MP3Extractor.h"
27#include "include/MPEG2PSExtractor.h"
28#include "include/MPEG2TSExtractor.h"
29#include "include/MPEG4Extractor.h"
30#include "include/NuCachedSource2.h"
31#include "include/OggExtractor.h"
32#include "include/WAVExtractor.h"
33#include "include/WVMExtractor.h"
34
35#include "matroska/MatroskaExtractor.h"
36
37#include <media/IMediaHTTPConnection.h>
38#include <media/IMediaHTTPService.h>
39#include <media/stagefright/foundation/ADebug.h>
40#include <media/stagefright/foundation/AMessage.h>
41#include <media/stagefright/DataSource.h>
42#include <media/stagefright/DataURISource.h>
43#include <media/stagefright/FileSource.h>
44#include <media/stagefright/MediaErrors.h>
45#include <media/stagefright/MediaHTTP.h>
46#include <utils/String8.h>
47
48#include <cutils/properties.h>
49
50namespace android {
51
52bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
53    *x = 0;
54
55    uint8_t byte[2];
56    if (readAt(offset, byte, 2) != 2) {
57        return false;
58    }
59
60    *x = (byte[0] << 8) | byte[1];
61
62    return true;
63}
64
65bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
66    *x = 0;
67
68    uint8_t byte[3];
69    if (readAt(offset, byte, 3) != 3) {
70        return false;
71    }
72
73    *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
74
75    return true;
76}
77
78bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
79    *x = 0;
80
81    uint32_t tmp;
82    if (readAt(offset, &tmp, 4) != 4) {
83        return false;
84    }
85
86    *x = ntohl(tmp);
87
88    return true;
89}
90
91bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
92    *x = 0;
93
94    uint64_t tmp;
95    if (readAt(offset, &tmp, 8) != 8) {
96        return false;
97    }
98
99    *x = ntoh64(tmp);
100
101    return true;
102}
103
104status_t DataSource::getSize(off64_t *size) {
105    *size = 0;
106
107    return ERROR_UNSUPPORTED;
108}
109
110////////////////////////////////////////////////////////////////////////////////
111
112Mutex DataSource::gSnifferMutex;
113List<DataSource::SnifferFunc> DataSource::gSniffers;
114bool DataSource::gSniffersRegistered = false;
115
116bool DataSource::sniff(
117        String8 *mimeType, float *confidence, sp<AMessage> *meta) {
118    *mimeType = "";
119    *confidence = 0.0f;
120    meta->clear();
121
122    {
123        Mutex::Autolock autoLock(gSnifferMutex);
124        if (!gSniffersRegistered) {
125            return false;
126        }
127    }
128
129    for (List<SnifferFunc>::iterator it = gSniffers.begin();
130         it != gSniffers.end(); ++it) {
131        String8 newMimeType;
132        float newConfidence;
133        sp<AMessage> newMeta;
134        if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
135            if (newConfidence > *confidence) {
136                *mimeType = newMimeType;
137                *confidence = newConfidence;
138                *meta = newMeta;
139            }
140        }
141    }
142
143    return *confidence > 0.0;
144}
145
146// static
147void DataSource::RegisterSniffer_l(SnifferFunc func) {
148    for (List<SnifferFunc>::iterator it = gSniffers.begin();
149         it != gSniffers.end(); ++it) {
150        if (*it == func) {
151            return;
152        }
153    }
154
155    gSniffers.push_back(func);
156}
157
158// static
159void DataSource::RegisterDefaultSniffers() {
160    Mutex::Autolock autoLock(gSnifferMutex);
161    if (gSniffersRegistered) {
162        return;
163    }
164
165    RegisterSniffer_l(SniffMPEG4);
166    RegisterSniffer_l(SniffMatroska);
167    RegisterSniffer_l(SniffOgg);
168    RegisterSniffer_l(SniffWAV);
169    RegisterSniffer_l(SniffFLAC);
170    RegisterSniffer_l(SniffAMR);
171    RegisterSniffer_l(SniffMPEG2TS);
172    RegisterSniffer_l(SniffMP3);
173    RegisterSniffer_l(SniffAAC);
174    RegisterSniffer_l(SniffMPEG2PS);
175    RegisterSniffer_l(SniffWVM);
176    RegisterSniffer_l(SniffMidi);
177
178    char value[PROPERTY_VALUE_MAX];
179    if (property_get("drm.service.enabled", value, NULL)
180            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
181        RegisterSniffer_l(SniffDRM);
182    }
183    gSniffersRegistered = true;
184}
185
186// static
187sp<DataSource> DataSource::CreateFromURI(
188        const sp<IMediaHTTPService> &httpService,
189        const char *uri,
190        const KeyedVector<String8, String8> *headers,
191        String8 *contentType,
192        HTTPBase *httpSource) {
193    if (contentType != NULL) {
194        *contentType = "";
195    }
196
197    bool isWidevine = !strncasecmp("widevine://", uri, 11);
198
199    sp<DataSource> source;
200    if (!strncasecmp("file://", uri, 7)) {
201        source = new FileSource(uri + 7);
202    } else if (!strncasecmp("http://", uri, 7)
203            || !strncasecmp("https://", uri, 8)
204            || isWidevine) {
205        if (httpService == NULL) {
206            ALOGE("Invalid http service!");
207            return NULL;
208        }
209
210        if (httpSource == NULL) {
211            sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
212            if (conn == NULL) {
213                ALOGE("Failed to make http connection from http service!");
214                return NULL;
215            }
216            httpSource = new MediaHTTP(conn);
217        }
218
219        String8 tmp;
220        if (isWidevine) {
221            tmp = String8("http://");
222            tmp.append(uri + 11);
223
224            uri = tmp.string();
225        }
226
227        String8 cacheConfig;
228        bool disconnectAtHighwatermark;
229        KeyedVector<String8, String8> nonCacheSpecificHeaders;
230        if (headers != NULL) {
231            nonCacheSpecificHeaders = *headers;
232            NuCachedSource2::RemoveCacheSpecificHeaders(
233                    &nonCacheSpecificHeaders,
234                    &cacheConfig,
235                    &disconnectAtHighwatermark);
236        }
237
238        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
239            ALOGE("Failed to connect http source!");
240            return NULL;
241        }
242
243        if (!isWidevine) {
244            if (contentType != NULL) {
245                *contentType = httpSource->getMIMEType();
246            }
247
248            source = new NuCachedSource2(
249                    httpSource,
250                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
251                    disconnectAtHighwatermark);
252        } else {
253            // We do not want that prefetching, caching, datasource wrapper
254            // in the widevine:// case.
255            source = httpSource;
256        }
257    } else if (!strncasecmp("data:", uri, 5)) {
258        source = DataURISource::Create(uri);
259    } else {
260        // Assume it's a filename.
261        source = new FileSource(uri);
262    }
263
264    if (source == NULL || source->initCheck() != OK) {
265        return NULL;
266    }
267
268    return source;
269}
270
271sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpService) {
272    if (httpService == NULL) {
273        return NULL;
274    }
275
276    sp<IMediaHTTPConnection> conn = httpService->makeHTTPConnection();
277    if (conn == NULL) {
278        return NULL;
279    } else {
280        return new MediaHTTP(conn);
281    }
282}
283
284String8 DataSource::getMIMEType() const {
285    return String8("application/octet-stream");
286}
287
288}  // namespace android
289