OSDN Git Service

ae20ad5f332866a8268ce6b3bc6b44d18d85622c
[android-x86/external-stagefright-plugins.git] / utils / ffmpeg_source.cpp
1 /*
2  * Copyright 2012 Michael Chen <omxcodec@gmail.com>
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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "FFMPEG"
19 #include <utils/Log.h>
20
21 #include <stdlib.h>
22 #include "ffmpeg_source.h"
23
24 #include <media/stagefright/DataSource.h>
25
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29
30 #include "config.h"
31 #include "libavformat/url.h"
32
33 #ifdef __cplusplus
34 }
35 #endif
36
37 namespace android {
38
39 class FFSource
40 {
41 public:
42     FFSource(DataSource *source);
43     int init_check();
44     int read(unsigned char *buf, size_t size);
45     int64_t seek(int64_t pos);
46     off64_t getSize();
47     ~FFSource();
48 protected:
49     sp<DataSource> mSource;
50     int64_t mOffset;
51 };
52
53 FFSource::FFSource(DataSource *source)
54     : mSource(source),
55       mOffset(0)
56 {
57 }
58
59 FFSource::~FFSource()
60 {
61         mSource = NULL;
62 }
63
64 int FFSource::init_check()
65 {
66     if (mSource->initCheck() != OK) {
67         ALOGE("FFSource initCheck failed");
68         return -1;
69     }
70
71     return 0;
72 }
73
74 int FFSource::read(unsigned char *buf, size_t size)
75 {
76     ssize_t n = 0;
77
78     n = mSource->readAt(mOffset, buf, size);
79     if (n == UNKNOWN_ERROR) {
80         ALOGE("FFSource readAt failed");
81         return AVERROR(errno);
82     }
83     if (n > 0) {
84         mOffset += n;
85     }
86
87     return n;
88 }
89
90 int64_t FFSource::seek(int64_t pos)
91 {
92     mOffset = pos;
93     return 0;
94 }
95
96 off64_t FFSource::getSize()
97 {
98     off64_t sz = -1;
99
100     if (mSource->getSize(&sz) != OK) {
101          ALOGE("FFSource getSize failed");
102          return AVERROR(errno);
103     }
104
105     return sz;
106 }
107
108 /////////////////////////////////////////////////////////////////
109
110 static int android_open(URLContext *h, const char *url, int flags __unused)
111 {
112     // the url in form of "android-source:<DataSource Ptr>",
113     // the DataSource Pointer passed by the ffmpeg extractor
114     DataSource *source = NULL;
115     char url_check[PATH_MAX] = {0};
116
117     ALOGV("android source begin open");
118
119     if (!url) {
120         ALOGE("android url is null!");
121         return -1;
122     }
123
124     ALOGV("android open, url: %s", url);
125     sscanf(url + strlen("android-source:"), "%p", &source);
126     if(source == NULL){
127         ALOGE("ffmpeg open data source error! (invalid source)");
128         return -1;
129     }
130
131     snprintf(url_check, sizeof(url_check), "android-source:%p",
132                 source);
133
134     if (strcmp(url_check, url) != 0) {
135
136         String8 uri = source->getUri();
137         if (!uri.string()) {
138             ALOGE("ffmpeg open data source error! (source uri)");
139             return -1;
140         }
141
142         snprintf(url_check, sizeof(url_check), "android-source:%p|file:%s",
143                     source, uri.string());
144
145         if (strcmp(url_check, url) != 0) {
146             ALOGE("ffmpeg open data source error! (url check)");
147             return -1;
148         }
149     }
150
151     ALOGV("ffmpeg open android data source success, source ptr: %p", source);
152
153     FFSource *ffs = new FFSource(source);
154     h->priv_data = (void *)ffs;
155
156     ALOGV("android source open success");
157
158     return 0;
159 }
160 static int android_read(URLContext *h, unsigned char *buf, int size)
161 {
162     FFSource* ffs = (FFSource *)h->priv_data;
163     return ffs->read(buf, size);
164 }
165
166 static int android_write(URLContext *h __unused, const unsigned char *buf __unused, int size __unused)
167 {
168     return -1;
169 }
170
171 static int64_t android_seek(URLContext *h, int64_t pos, int whence)
172 {
173     FFSource* ffs = (FFSource*)h->priv_data;
174
175     if (whence == AVSEEK_SIZE) {
176         return ffs->getSize();
177     }
178
179     ffs->seek(pos);
180     return 0;
181 }
182
183 static int android_close(URLContext *h)
184 {
185     FFSource* ffs = (FFSource*)h->priv_data;
186     ALOGV("android source close");
187     delete ffs;
188     h->priv_data = NULL;
189     return 0;
190 }
191
192 static int android_get_handle(URLContext *h)
193 {
194     return (intptr_t)h->priv_data;
195 }
196
197 static int android_check(URLContext *h, int mask)
198 {
199     FFSource* ffs = (FFSource*)h->priv_data;
200
201     /* url_check does not guarantee url_open will be called
202      * (and actually it is not designed to do so)
203      * If url_open is not called before url_check called, ffs
204      * will be null, and we will assume everything is ok.
205      */
206     if (ffs && (ffs->init_check() < 0))
207         return AVERROR(EACCES); // FIXME
208
209     return (mask & AVIO_FLAG_READ);
210 }
211
212 static URLProtocol ff_android_protocol;
213
214 void ffmpeg_register_android_source()
215 {
216     memset(&ff_android_protocol, 0, sizeof(URLProtocol));
217     ff_android_protocol.name                = "android-source";
218     ff_android_protocol.url_open            = android_open;
219     ff_android_protocol.url_read            = android_read;
220     ff_android_protocol.url_write           = android_write;
221     ff_android_protocol.url_seek            = android_seek;
222     ff_android_protocol.url_close           = android_close;
223     ff_android_protocol.url_get_file_handle = android_get_handle;
224     ff_android_protocol.url_check           = android_check;
225     
226     ffurl_register_protocol(&ff_android_protocol);
227 }
228
229 }  // namespace android