1/*
2 * Copyright 2004-2010, Marcus Overhagen. All rights reserved.
3 * Copyright 2016, Dario Casalinuovo. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <AdapterIO.h>
9#include <AutoDeleter.h>
10#include <Autolock.h>
11#include <BufferIO.h>
12#include <DataIO.h>
13#include <image.h>
14#include <Path.h>
15
16#include <string.h>
17
18#include "AddOnManager.h"
19#include "PluginManager.h"
20#include "DataExchange.h"
21#include "MediaDebug.h"
22
23
24PluginManager gPluginManager;
25
26#define BLOCK_SIZE 4096
27#define MAX_STREAMERS 40
28
29
30class DataIOAdapter : public BAdapterIO {
31public:
32	DataIOAdapter(BDataIO* dataIO)
33		:
34		BAdapterIO(B_MEDIA_SEEK_BACKWARD | B_MEDIA_MUTABLE_SIZE,
35			B_INFINITE_TIMEOUT),
36		fDataIO(dataIO)
37	{
38		fDataInputAdapter = BuildInputAdapter();
39	}
40
41	virtual	~DataIOAdapter()
42	{
43	}
44
45	virtual	ssize_t	ReadAt(off_t position, void* buffer,
46		size_t size)
47	{
48		if (position == Position()) {
49			ssize_t ret = fDataIO->Read(buffer, size);
50			fDataInputAdapter->Write(buffer, ret);
51			return ret;
52		}
53
54		off_t totalSize = 0;
55		if (GetSize(&totalSize) != B_OK)
56			return B_UNSUPPORTED;
57
58		if (position+size < (size_t)totalSize)
59			return ReadAt(position, buffer, size);
60
61		return B_NOT_SUPPORTED;
62	}
63
64	virtual	ssize_t	WriteAt(off_t position, const void* buffer,
65		size_t size)
66	{
67		if (position == Position()) {
68			ssize_t ret = fDataIO->Write(buffer, size);
69			fDataInputAdapter->Write(buffer, ret);
70			return ret;
71		}
72
73		return B_NOT_SUPPORTED;
74	}
75
76private:
77	BDataIO*		fDataIO;
78	BInputAdapter*	fDataInputAdapter;
79};
80
81
82class BMediaIOWrapper : public BMediaIO {
83public:
84	BMediaIOWrapper(BDataIO* source)
85		:
86		fData(NULL),
87		fPosition(NULL),
88		fMedia(NULL),
89		fDataIOAdapter(NULL),
90		fErr(B_NO_ERROR)
91	{
92		CALLED();
93
94		fPosition = dynamic_cast<BPositionIO*>(source);
95		fMedia = dynamic_cast<BMediaIO*>(source);
96		fData = source;
97
98		if (!IsPosition()) {
99			// In this case we have to supply our own form
100			// of pseudo-seekable object from a non-seekable
101			// BDataIO.
102			fDataIOAdapter = new DataIOAdapter(source);
103			fMedia = dynamic_cast<BMediaIO*>(fDataIOAdapter);
104			fPosition = dynamic_cast<BPositionIO*>(fDataIOAdapter);
105			fData = dynamic_cast<BDataIO*>(fDataIOAdapter);
106			TRACE("Unable to improve performance with a BufferIO\n");
107		}
108
109		if (IsMedia())
110			fMedia->GetFlags(&fFlags);
111		else if (IsPosition())
112			fFlags = B_MEDIA_SEEKABLE;
113	}
114
115	virtual	~BMediaIOWrapper()
116	{
117		if (fDataIOAdapter != NULL)
118			delete fDataIOAdapter;
119	}
120
121	status_t InitCheck() const
122	{
123		return fErr;
124	}
125
126	// BMediaIO interface
127
128	virtual void GetFlags(int32* flags) const
129	{
130		*flags = fFlags;
131	}
132
133	// BPositionIO interface
134
135	virtual	ssize_t ReadAt(off_t position, void* buffer,
136		size_t size)
137	{
138		CALLED();
139
140		return fPosition->ReadAt(position, buffer, size);
141	}
142
143	virtual	ssize_t WriteAt(off_t position, const void* buffer,
144		size_t size)
145	{
146		CALLED();
147
148		return fPosition->WriteAt(position, buffer, size);
149	}
150
151	virtual	off_t Seek(off_t position, uint32 seekMode)
152	{
153		CALLED();
154
155		return fPosition->Seek(position, seekMode);
156
157	}
158
159	virtual off_t Position() const
160	{
161		CALLED();
162
163		return fPosition->Position();
164	}
165
166	virtual	status_t SetSize(off_t size)
167	{
168		CALLED();
169
170		return fPosition->SetSize(size);
171	}
172
173	virtual	status_t GetSize(off_t* size) const
174	{
175		CALLED();
176
177		return fPosition->GetSize(size);
178	}
179
180protected:
181
182	bool IsMedia() const
183	{
184		return fMedia != NULL;
185	}
186
187	bool IsPosition() const
188	{
189		return fPosition != NULL;
190	}
191
192private:
193	BDataIO*			fData;
194	BPositionIO*		fPosition;
195	BMediaIO*			fMedia;
196	DataIOAdapter*		fDataIOAdapter;
197
198	int32				fFlags;
199
200	status_t			fErr;
201};
202
203
204// #pragma mark - Readers/Decoders
205
206
207status_t
208PluginManager::CreateReader(Reader** reader, int32* streamCount,
209	media_file_format* mff, BDataIO* source)
210{
211	TRACE("PluginManager::CreateReader enter\n");
212
213	// The wrapper class will present our source in a more useful
214	// way, we create an instance which is buffering our reads and
215	// writes.
216	BMediaIOWrapper* buffered_source = new BMediaIOWrapper(source);
217	ObjectDeleter<BMediaIOWrapper> ioDeleter(buffered_source);
218
219	status_t ret = buffered_source->InitCheck();
220	if (ret != B_OK)
221		return ret;
222
223	// get list of available readers from the server
224	entry_ref refs[MAX_READERS];
225	int32 count;
226
227	ret = AddOnManager::GetInstance()->GetReaders(refs, &count,
228		MAX_READERS);
229	if (ret != B_OK) {
230		printf("PluginManager::CreateReader: can't get list of readers: %s\n",
231			strerror(ret));
232		return ret;
233	}
234
235	// try each reader by calling it's Sniff function...
236	for (int32 i = 0; i < count; i++) {
237		const entry_ref& ref = refs[i];
238		MediaPlugin* plugin = GetPlugin(ref);
239		if (plugin == NULL) {
240			printf("PluginManager::CreateReader: GetPlugin failed\n");
241			return B_ERROR;
242		}
243
244		ReaderPlugin* readerPlugin = dynamic_cast<ReaderPlugin*>(plugin);
245		if (readerPlugin == NULL) {
246			printf("PluginManager::CreateReader: dynamic_cast failed\n");
247			PutPlugin(plugin);
248			return B_ERROR;
249		}
250
251		*reader = readerPlugin->NewReader();
252		if (*reader == NULL) {
253			printf("PluginManager::CreateReader: NewReader failed\n");
254			PutPlugin(plugin);
255			return B_ERROR;
256		}
257
258		buffered_source->Seek(0, SEEK_SET);
259		(*reader)->Setup(buffered_source);
260		(*reader)->fMediaPlugin = plugin;
261
262		if ((*reader)->Sniff(streamCount) == B_OK) {
263			TRACE("PluginManager::CreateReader: Sniff success "
264				"(%" B_PRId32 " stream(s))\n", *streamCount);
265			(*reader)->GetFileFormatInfo(mff);
266			ioDeleter.Detach();
267			return B_OK;
268		}
269
270		DestroyReader(*reader);
271		*reader = NULL;
272	}
273
274	TRACE("PluginManager::CreateReader leave\n");
275	return B_MEDIA_NO_HANDLER;
276}
277
278
279void
280PluginManager::DestroyReader(Reader* reader)
281{
282	if (reader != NULL) {
283		TRACE("PluginManager::DestroyReader(%p (plugin: %p))\n", reader,
284			reader->fMediaPlugin);
285		// NOTE: We have to put the plug-in after deleting the reader,
286		// since otherwise we may actually unload the code for the
287		// destructor...
288		MediaPlugin* plugin = reader->fMediaPlugin;
289		delete reader;
290		PutPlugin(plugin);
291	}
292}
293
294
295status_t
296PluginManager::CreateDecoder(Decoder** _decoder, const media_format& format)
297{
298	TRACE("PluginManager::CreateDecoder enter\n");
299
300	// get decoder for this format
301	entry_ref ref;
302	status_t ret = AddOnManager::GetInstance()->GetDecoderForFormat(
303		&ref, format);
304	if (ret != B_OK) {
305		printf("PluginManager::CreateDecoder: can't get decoder for format: "
306			"%s\n", strerror(ret));
307		return ret;
308	}
309
310	MediaPlugin* plugin = GetPlugin(ref);
311	if (plugin == NULL) {
312		printf("PluginManager::CreateDecoder: GetPlugin failed\n");
313		return B_ERROR;
314	}
315
316	DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin);
317	if (decoderPlugin == NULL) {
318		printf("PluginManager::CreateDecoder: dynamic_cast failed\n");
319		PutPlugin(plugin);
320		return B_ERROR;
321	}
322
323	// TODO: In theory, one DecoderPlugin could support multiple Decoders,
324	// but this is not yet handled (passing "0" as index/ID).
325	*_decoder = decoderPlugin->NewDecoder(0);
326	if (*_decoder == NULL) {
327		printf("PluginManager::CreateDecoder: NewDecoder() failed\n");
328		PutPlugin(plugin);
329		return B_ERROR;
330	}
331	TRACE("  created decoder: %p\n", *_decoder);
332	(*_decoder)->fMediaPlugin = plugin;
333
334	TRACE("PluginManager::CreateDecoder leave\n");
335
336	return B_OK;
337}
338
339
340status_t
341PluginManager::CreateDecoder(Decoder** decoder, const media_codec_info& mci)
342{
343	TRACE("PluginManager::CreateDecoder enter\n");
344	entry_ref ref;
345	status_t status = AddOnManager::GetInstance()->GetEncoder(&ref, mci.id);
346	if (status != B_OK)
347		return status;
348
349	MediaPlugin* plugin = GetPlugin(ref);
350	if (plugin == NULL) {
351		ERROR("PluginManager::CreateDecoder: GetPlugin failed\n");
352		return B_ERROR;
353	}
354
355	DecoderPlugin* decoderPlugin = dynamic_cast<DecoderPlugin*>(plugin);
356	if (decoderPlugin == NULL) {
357		ERROR("PluginManager::CreateDecoder: dynamic_cast failed\n");
358		PutPlugin(plugin);
359		return B_ERROR;
360	}
361
362	// TODO: In theory, one DecoderPlugin could support multiple Decoders,
363	// but this is not yet handled (passing "0" as index/ID).
364	*decoder = decoderPlugin->NewDecoder(0);
365	if (*decoder == NULL) {
366		ERROR("PluginManager::CreateDecoder: NewDecoder() failed\n");
367		PutPlugin(plugin);
368		return B_ERROR;
369	}
370	TRACE("  created decoder: %p\n", *decoder);
371	(*decoder)->fMediaPlugin = plugin;
372
373	TRACE("PluginManager::CreateDecoder leave\n");
374
375	return B_OK;
376
377}
378
379
380status_t
381PluginManager::GetDecoderInfo(Decoder* decoder, media_codec_info* _info) const
382{
383	if (decoder == NULL)
384		return B_BAD_VALUE;
385
386	decoder->GetCodecInfo(_info);
387	// TODO:
388	// out_info->id =
389	// out_info->sub_id =
390	return B_OK;
391}
392
393
394void
395PluginManager::DestroyDecoder(Decoder* decoder)
396{
397	if (decoder != NULL) {
398		TRACE("PluginManager::DestroyDecoder(%p, plugin: %p)\n", decoder,
399			decoder->fMediaPlugin);
400		// NOTE: We have to put the plug-in after deleting the decoder,
401		// since otherwise we may actually unload the code for the
402		// destructor...
403		MediaPlugin* plugin = decoder->fMediaPlugin;
404		delete decoder;
405		PutPlugin(plugin);
406	}
407}
408
409
410// #pragma mark - Writers/Encoders
411
412
413status_t
414PluginManager::CreateWriter(Writer** writer, const media_file_format& mff,
415	BDataIO* target)
416{
417	TRACE("PluginManager::CreateWriter enter\n");
418
419	// Get the Writer responsible for this media_file_format from the server.
420	entry_ref ref;
421	status_t ret = AddOnManager::GetInstance()->GetWriter(&ref,
422		mff.id.internal_id);
423	if (ret != B_OK) {
424		printf("PluginManager::CreateWriter: can't get writer for file "
425			"family: %s\n", strerror(ret));
426		return ret;
427	}
428
429	MediaPlugin* plugin = GetPlugin(ref);
430	if (plugin == NULL) {
431		printf("PluginManager::CreateWriter: GetPlugin failed\n");
432		return B_ERROR;
433	}
434
435	WriterPlugin* writerPlugin = dynamic_cast<WriterPlugin*>(plugin);
436	if (writerPlugin == NULL) {
437		printf("PluginManager::CreateWriter: dynamic_cast failed\n");
438		PutPlugin(plugin);
439		return B_ERROR;
440	}
441
442	*writer = writerPlugin->NewWriter();
443	if (*writer == NULL) {
444		printf("PluginManager::CreateWriter: NewWriter failed\n");
445		PutPlugin(plugin);
446		return B_ERROR;
447	}
448
449	(*writer)->Setup(target);
450	(*writer)->fMediaPlugin = plugin;
451
452	TRACE("PluginManager::CreateWriter leave\n");
453	return B_OK;
454}
455
456
457void
458PluginManager::DestroyWriter(Writer* writer)
459{
460	if (writer != NULL) {
461		TRACE("PluginManager::DestroyWriter(%p (plugin: %p))\n", writer,
462			writer->fMediaPlugin);
463		// NOTE: We have to put the plug-in after deleting the writer,
464		// since otherwise we may actually unload the code for the
465		// destructor...
466		MediaPlugin* plugin = writer->fMediaPlugin;
467		delete writer;
468		PutPlugin(plugin);
469	}
470}
471
472
473status_t
474PluginManager::CreateEncoder(Encoder** _encoder,
475	const media_codec_info* codecInfo, uint32 flags)
476{
477	TRACE("PluginManager::CreateEncoder enter\n");
478
479	// Get encoder for this codec info from the server
480	entry_ref ref;
481	status_t ret = AddOnManager::GetInstance()->GetEncoder(&ref,
482		codecInfo->id);
483	if (ret != B_OK) {
484		printf("PluginManager::CreateEncoder: can't get encoder for codec %s: "
485			"%s\n", codecInfo->pretty_name, strerror(ret));
486		return ret;
487	}
488
489	MediaPlugin* plugin = GetPlugin(ref);
490	if (!plugin) {
491		printf("PluginManager::CreateEncoder: GetPlugin failed\n");
492		return B_ERROR;
493	}
494
495	EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin);
496	if (encoderPlugin == NULL) {
497		printf("PluginManager::CreateEncoder: dynamic_cast failed\n");
498		PutPlugin(plugin);
499		return B_ERROR;
500	}
501
502	*_encoder = encoderPlugin->NewEncoder(*codecInfo);
503	if (*_encoder == NULL) {
504		printf("PluginManager::CreateEncoder: NewEncoder() failed\n");
505		PutPlugin(plugin);
506		return B_ERROR;
507	}
508	TRACE("  created encoder: %p\n", *_encoder);
509	(*_encoder)->fMediaPlugin = plugin;
510
511	TRACE("PluginManager::CreateEncoder leave\n");
512
513	return B_OK;
514}
515
516
517status_t
518PluginManager::CreateEncoder(Encoder** encoder, const media_format& format)
519{
520	TRACE("PluginManager::CreateEncoder enter nr2\n");
521
522	entry_ref ref;
523
524	status_t ret = AddOnManager::GetInstance()->GetEncoderForFormat(
525		&ref, format);
526
527	if (ret != B_OK) {
528		ERROR("PluginManager::CreateEncoder: can't get decoder for format: "
529			"%s\n", strerror(ret));
530		return ret;
531	}
532
533	MediaPlugin* plugin = GetPlugin(ref);
534	if (plugin == NULL) {
535		ERROR("PluginManager::CreateEncoder: GetPlugin failed\n");
536		return B_ERROR;
537	}
538
539	EncoderPlugin* encoderPlugin = dynamic_cast<EncoderPlugin*>(plugin);
540	if (encoderPlugin == NULL) {
541		ERROR("PluginManager::CreateEncoder: dynamic_cast failed\n");
542		PutPlugin(plugin);
543		return B_ERROR;
544	}
545
546
547	*encoder = encoderPlugin->NewEncoder(format);
548	if (*encoder == NULL) {
549		ERROR("PluginManager::CreateEncoder: NewEncoder() failed\n");
550		PutPlugin(plugin);
551		return B_ERROR;
552	}
553	TRACE("  created encoder: %p\n", *encoder);
554	(*encoder)->fMediaPlugin = plugin;
555
556	TRACE("PluginManager::CreateEncoder leave nr2\n");
557
558	return B_OK;
559}
560
561
562void
563PluginManager::DestroyEncoder(Encoder* encoder)
564{
565	if (encoder != NULL) {
566		TRACE("PluginManager::DestroyEncoder(%p, plugin: %p)\n", encoder,
567			encoder->fMediaPlugin);
568		// NOTE: We have to put the plug-in after deleting the encoder,
569		// since otherwise we may actually unload the code for the
570		// destructor...
571		MediaPlugin* plugin = encoder->fMediaPlugin;
572		delete encoder;
573		PutPlugin(plugin);
574	}
575}
576
577
578status_t
579PluginManager::CreateStreamer(Streamer** streamer, BUrl url, BDataIO** source)
580{
581	BAutolock _(fLocker);
582
583	TRACE("PluginManager::CreateStreamer enter\n");
584
585	entry_ref refs[MAX_STREAMERS];
586	int32 count;
587
588	status_t ret = AddOnManager::GetInstance()->GetStreamers(refs, &count,
589		MAX_STREAMERS);
590	if (ret != B_OK) {
591		printf("PluginManager::CreateStreamer: can't get list of streamers:"
592			" %s\n", strerror(ret));
593		return ret;
594	}
595
596	// try each reader by calling it's Sniff function...
597	for (int32 i = 0; i < count; i++) {
598		entry_ref ref = refs[i];
599		MediaPlugin* plugin = GetPlugin(ref);
600		if (plugin == NULL) {
601			printf("PluginManager::CreateStreamer: GetPlugin failed\n");
602			return B_ERROR;
603		}
604
605		StreamerPlugin* streamerPlugin = dynamic_cast<StreamerPlugin*>(plugin);
606		if (streamerPlugin == NULL) {
607			printf("PluginManager::CreateStreamer: dynamic_cast failed\n");
608			PutPlugin(plugin);
609			return B_ERROR;
610		}
611
612		*streamer = streamerPlugin->NewStreamer();
613		if (*streamer == NULL) {
614			printf("PluginManager::CreateStreamer: NewReader failed\n");
615			PutPlugin(plugin);
616			return B_ERROR;
617		}
618
619		(*streamer)->fMediaPlugin = plugin;
620		plugin->fRefCount++;
621
622		BDataIO* streamSource = NULL;
623		if ((*streamer)->Sniff(url, &streamSource) == B_OK) {
624			TRACE("PluginManager::CreateStreamer: Sniff success\n");
625			*source = streamSource;
626			return B_OK;
627		}
628
629		DestroyStreamer(*streamer);
630		*streamer = NULL;
631	}
632
633	TRACE("PluginManager::CreateStreamer leave\n");
634	return B_MEDIA_NO_HANDLER;
635}
636
637
638void
639PluginManager::DestroyStreamer(Streamer* streamer)
640{
641	BAutolock _(fLocker);
642
643	if (streamer != NULL) {
644		TRACE("PluginManager::DestroyStreamer(%p, plugin: %p)\n", streamer,
645			streamer->fMediaPlugin);
646
647		// NOTE: We have to put the plug-in after deleting the streamer,
648		// since otherwise we may actually unload the code for the
649		// destructor...
650		MediaPlugin* plugin = streamer->fMediaPlugin;
651		delete streamer;
652
653		// Delete the plugin only when every reference is released
654		if (plugin->fRefCount == 1) {
655			plugin->fRefCount = 0;
656			PutPlugin(plugin);
657		} else
658			plugin->fRefCount--;
659	}
660}
661
662
663// #pragma mark -
664
665
666PluginManager::PluginManager()
667	:
668	fPluginList(),
669	fLocker("media plugin manager")
670{
671	CALLED();
672}
673
674
675PluginManager::~PluginManager()
676{
677	CALLED();
678	for (int i = fPluginList.CountItems() - 1; i >= 0; i--) {
679		plugin_info* info = NULL;
680		fPluginList.Get(i, &info);
681		TRACE("PluginManager: Error, unloading PlugIn %s with usecount "
682			"%d\n", info->name, info->usecount);
683		delete info->plugin;
684		unload_add_on(info->image);
685	}
686}
687
688
689MediaPlugin*
690PluginManager::GetPlugin(const entry_ref& ref)
691{
692	TRACE("PluginManager::GetPlugin(%s)\n", ref.name);
693	fLocker.Lock();
694
695	MediaPlugin* plugin;
696	plugin_info* pinfo;
697	plugin_info info;
698
699	for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) {
700		if (0 == strcmp(ref.name, pinfo->name)) {
701			plugin = pinfo->plugin;
702			pinfo->usecount++;
703			TRACE("  found existing plugin: %p\n", pinfo->plugin);
704			fLocker.Unlock();
705			return plugin;
706		}
707	}
708
709	if (_LoadPlugin(ref, &info.plugin, &info.image) < B_OK) {
710		printf("PluginManager: Error, loading PlugIn %s failed\n", ref.name);
711		fLocker.Unlock();
712		return NULL;
713	}
714
715	strcpy(info.name, ref.name);
716	info.usecount = 1;
717	fPluginList.Insert(info);
718
719	TRACE("PluginManager: PlugIn %s loaded\n", ref.name);
720
721	plugin = info.plugin;
722	TRACE("  loaded plugin: %p\n", plugin);
723
724	fLocker.Unlock();
725	return plugin;
726}
727
728
729void
730PluginManager::PutPlugin(MediaPlugin* plugin)
731{
732	TRACE("PluginManager::PutPlugin()\n");
733	fLocker.Lock();
734
735	plugin_info* pinfo;
736
737	for (fPluginList.Rewind(); fPluginList.GetNext(&pinfo); ) {
738		if (plugin == pinfo->plugin) {
739			pinfo->usecount--;
740			if (pinfo->usecount == 0) {
741				TRACE("  deleting %p\n", pinfo->plugin);
742				delete pinfo->plugin;
743				TRACE("  unloading add-on: %" B_PRId32 "\n\n", pinfo->image);
744				unload_add_on(pinfo->image);
745				fPluginList.RemoveCurrent();
746			}
747			fLocker.Unlock();
748			return;
749		}
750	}
751
752	printf("PluginManager: Error, can't put PlugIn %p\n", plugin);
753
754	fLocker.Unlock();
755}
756
757
758status_t
759PluginManager::_LoadPlugin(const entry_ref& ref, MediaPlugin** plugin,
760	image_id* image)
761{
762	BPath p(&ref);
763
764	TRACE("PluginManager: _LoadPlugin trying to load %s\n", p.Path());
765
766	image_id id;
767	id = load_add_on(p.Path());
768	if (id < 0) {
769		printf("PluginManager: Error, load_add_on(): %s\n", strerror(id));
770		return B_ERROR;
771	}
772
773	MediaPlugin* (*instantiate_plugin_func)();
774
775	if (get_image_symbol(id, "instantiate_plugin", B_SYMBOL_TYPE_TEXT,
776			(void**)&instantiate_plugin_func) < B_OK) {
777		printf("PluginManager: Error, _LoadPlugin can't find "
778			"instantiate_plugin in %s\n", p.Path());
779		unload_add_on(id);
780		return B_ERROR;
781	}
782
783	MediaPlugin *pl;
784
785	pl = (*instantiate_plugin_func)();
786	if (pl == NULL) {
787		printf("PluginManager: Error, _LoadPlugin instantiate_plugin in %s "
788			"returned NULL\n", p.Path());
789		unload_add_on(id);
790		return B_ERROR;
791	}
792
793	*plugin = pl;
794	*image = id;
795	return B_OK;
796}
797