xref: /haiku/src/kits/media/PluginManager.cpp (revision 7200c6f499191933e4b04e1f9c9a269d10fc92c0)
1 /*
2 ** Copyright 2004-2007, Marcus Overhagen. All rights reserved.
3 ** Distributed under the terms of the OpenBeOS License.
4 */
5 
6 
7 #include <Path.h>
8 #include <image.h>
9 #include <string.h>
10 
11 #include "PluginManager.h"
12 #include "DataExchange.h"
13 #include "debug.h"
14 
15 
16 PluginManager _plugin_manager;
17 
18 
19 status_t
20 PluginManager::CreateReader(Reader **reader, int32 *streamCount,
21 	media_file_format *mff, BDataIO *source)
22 {
23 	TRACE("PluginManager::CreateReader enter\n");
24 
25 	BPositionIO *seekable_source = dynamic_cast<BPositionIO *>(source);
26 	if (seekable_source == 0) {
27 		printf("PluginManager::CreateReader: non-seekable sources not "
28 			"supported yet\n");
29 		return B_ERROR;
30 	}
31 
32 	// get list of available readers from the server
33 	server_get_readers_request request;
34 	server_get_readers_reply reply;
35 	status_t ret = QueryServer(SERVER_GET_READERS, &request, sizeof(request),
36 		&reply, sizeof(reply));
37 	if (ret != B_OK) {
38 		printf("PluginManager::CreateReader: can't get list of readers: %s\n",
39 			strerror(ret));
40 		return ret;
41 	}
42 
43 	// try each reader by calling it's Sniff function...
44 	for (int32 i = 0; i < reply.count; i++) {
45 		entry_ref ref = reply.ref[i];
46 		MediaPlugin *plugin = GetPlugin(ref);
47 		if (!plugin) {
48 			printf("PluginManager::CreateReader: GetPlugin failed\n");
49 			return B_ERROR;
50 		}
51 
52 		ReaderPlugin *readerPlugin = dynamic_cast<ReaderPlugin*>(plugin);
53 		if (!readerPlugin) {
54 			printf("PluginManager::CreateReader: dynamic_cast failed\n");
55 			PutPlugin(plugin);
56 			return B_ERROR;
57 		}
58 
59 		*reader = readerPlugin->NewReader();
60 		if (*reader == NULL) {
61 			printf("PluginManager::CreateReader: NewReader failed\n");
62 			PutPlugin(plugin);
63 			return B_ERROR;
64 		}
65 
66 		seekable_source->Seek(0, SEEK_SET);
67 		(*reader)->Setup(seekable_source);
68 		(*reader)->fMediaPlugin = plugin;
69 
70 		if ((*reader)->Sniff(streamCount) == B_OK) {
71 			TRACE("PluginManager::CreateReader: Sniff success "
72 				"(%ld stream(s))\n", *streamCount);
73 			(*reader)->GetFileFormatInfo(mff);
74 			return B_OK;
75 		}
76 
77 		DestroyReader(*reader);
78 	}
79 
80 	TRACE("PluginManager::CreateReader leave\n");
81 	return B_MEDIA_NO_HANDLER;
82 }
83 
84 
85 void
86 PluginManager::DestroyReader(Reader* reader)
87 {
88 	if (reader != NULL) {
89 		TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader,
90 			reader->fMediaPlugin);
91 		// NOTE: We have to put the plug-in after deleting the reader,
92 		// since otherwise we may actually unload the code for the
93 		// destructor...
94 		MediaPlugin* plugin = reader->fMediaPlugin;
95 		delete reader;
96 		PutPlugin(plugin);
97 	}
98 }
99 
100 
101 status_t
102 PluginManager::CreateDecoder(Decoder **_decoder, const media_format &format)
103 {
104 	TRACE("PluginManager::CreateDecoder enter\n");
105 
106 	// get decoder for this format from the server
107 	server_get_decoder_for_format_request request;
108 	server_get_decoder_for_format_reply reply;
109 	request.format = format;
110 	status_t ret = QueryServer(SERVER_GET_DECODER_FOR_FORMAT, &request,
111 		sizeof(request), &reply, sizeof(reply));
112 	if (ret != B_OK) {
113 		printf("PluginManager::CreateDecoder: can't get decoder for format: "
114 			"%s\n", strerror(ret));
115 		return ret;
116 	}
117 
118 	MediaPlugin* plugin = GetPlugin(reply.ref);
119 	if (!plugin) {
120 		printf("PluginManager::CreateDecoder: GetPlugin failed\n");
121 		return B_ERROR;
122 	}
123 
124 	DecoderPlugin *decoderPlugin = dynamic_cast<DecoderPlugin *>(plugin);
125 	if (!decoderPlugin) {
126 		printf("PluginManager::CreateDecoder: dynamic_cast failed\n");
127 		PutPlugin(plugin);
128 		return B_ERROR;
129 	}
130 
131 	*_decoder = decoderPlugin->NewDecoder(0);
132 	if (*_decoder == NULL) {
133 		printf("PluginManager::CreateDecoder: NewDecoder() failed\n");
134 		PutPlugin(plugin);
135 		return B_ERROR;
136 	}
137 	TRACE("  created decoder: %p\n", *_decoder);
138 	(*_decoder)->fMediaPlugin = plugin;
139 
140 	TRACE("PluginManager::CreateDecoder leave\n");
141 
142 	return B_OK;
143 }
144 
145 
146 status_t
147 PluginManager::CreateDecoder(Decoder **decoder, const media_codec_info &mci)
148 {
149 	// TODO
150 	debugger("not implemented");
151 	return B_ERROR;
152 }
153 
154 
155 status_t
156 PluginManager::GetDecoderInfo(Decoder *decoder,
157 	media_codec_info *out_info) const
158 {
159 	if (!decoder)
160 		return B_BAD_VALUE;
161 
162 	decoder->GetCodecInfo(out_info);
163 	// TODO:
164 	// out_info->id =
165 	// out_info->sub_id =
166 	return B_OK;
167 }
168 
169 
170 void
171 PluginManager::DestroyDecoder(Decoder *decoder)
172 {
173 	if (decoder != NULL) {
174 		TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder,
175 			decoder->fMediaPlugin);
176 		// NOTE: We have to put the plug-in after deleting the decoder,
177 		// since otherwise we may actually unload the code for the
178 		// destructor...
179 		MediaPlugin* plugin = decoder->fMediaPlugin;
180 		delete decoder;
181 		PutPlugin(plugin);
182 	}
183 }
184 
185 
186 //	#pragma mark -
187 
188 
189 PluginManager::PluginManager()
190 {
191 	CALLED();
192 	fLocker = new BLocker;
193 	fPluginList = new List<plugin_info>;
194 }
195 
196 
197 PluginManager::~PluginManager()
198 {
199 	CALLED();
200 	for (int i = fPluginList->CountItems() - 1; i >= 0; i--) {
201 		plugin_info *info = NULL;
202 		fPluginList->Get(i, &info);
203 		printf("PluginManager: Error, unloading PlugIn %s with usecount "
204 			"%d\n", info->name, info->usecount);
205 		delete info->plugin;
206 		unload_add_on(info->image);
207 	}
208 	delete fLocker;
209 }
210 
211 
212 MediaPlugin *
213 PluginManager::GetPlugin(const entry_ref &ref)
214 {
215 	TRACE("PluginManager::GetPlugin(%s)\n", ref.name);
216 	fLocker->Lock();
217 
218 	MediaPlugin *plugin;
219 	plugin_info *pinfo;
220 	plugin_info info;
221 
222 	for (fPluginList->Rewind(); fPluginList->GetNext(&pinfo); ) {
223 		if (0 == strcmp(ref.name, pinfo->name)) {
224 			plugin = pinfo->plugin;
225 			pinfo->usecount++;
226 			TRACE("  found existing plugin: %p\n", pinfo->plugin);
227 			fLocker->Unlock();
228 			return plugin;
229 		}
230 	}
231 
232 	if (LoadPlugin(ref, &info.plugin, &info.image) < B_OK) {
233 		printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name);
234 		fLocker->Unlock();
235 		return NULL;
236 	}
237 
238 	strcpy(info.name, ref.name);
239 	info.usecount = 1;
240 	fPluginList->Insert(info);
241 
242 	TRACE("PluginManager: PlugIn %s loaded\n", ref.name);
243 
244 	plugin = info.plugin;
245 	TRACE("  loaded plugin: %p\n", plugin);
246 
247 	fLocker->Unlock();
248 	return plugin;
249 }
250 
251 
252 void
253 PluginManager::PutPlugin(MediaPlugin* plugin)
254 {
255 	TRACE("PluginManager::PutPlugin()\n");
256 	fLocker->Lock();
257 
258 	plugin_info *pinfo;
259 
260 	for (fPluginList->Rewind(); fPluginList->GetNext(&pinfo); ) {
261 		if (plugin == pinfo->plugin) {
262 			pinfo->usecount--;
263 			if (pinfo->usecount == 0) {
264 				TRACE("  deleting %p\n", pinfo->plugin);
265 				delete pinfo->plugin;
266 				TRACE("  unloading add-on: %ld\n\n", pinfo->image);
267 				unload_add_on(pinfo->image);
268 				fPluginList->RemoveCurrent();
269 			}
270 			fLocker->Unlock();
271 			return;
272 		}
273 	}
274 
275 	printf("PluginManager: Error, can't put PlugIn %p\n", plugin);
276 
277 	fLocker->Unlock();
278 }
279 
280 
281 status_t
282 PluginManager::LoadPlugin(const entry_ref &ref, MediaPlugin **plugin,
283 	image_id *image)
284 {
285 	BPath p(&ref);
286 
287 	TRACE("PluginManager: LoadPlugin trying to load %s\n", p.Path());
288 
289 	image_id id;
290 	id = load_add_on(p.Path());
291 	TRACE("  loaded add-on: %ld\n", id);
292 	if (id < 0)
293 		return B_ERROR;
294 
295 	MediaPlugin *(*instantiate_plugin_func)();
296 
297 	if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT,
298 			(void**)&instantiate_plugin_func) < B_OK) {
299 		printf("PluginManager: Error, LoadPlugin can't find "
300 			"instantiate_plugin in %s\n", p.Path());
301 		unload_add_on(id);
302 		return B_ERROR;
303 	}
304 
305 	MediaPlugin *pl;
306 
307 	pl = (*instantiate_plugin_func)();
308 	if (pl == NULL) {
309 		printf("PluginManager: Error, LoadPlugin instantiate_plugin in %s "
310 			"returned NULL\n", p.Path());
311 		unload_add_on(id);
312 		return B_ERROR;
313 	}
314 
315 	*plugin = pl;
316 	*image = id;
317 	return B_OK;
318 }
319