OSDN Git Service

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