1/*
2 * Copyright 2004-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		Axel D��rfler
7 *		Marcus Overhagen
8 */
9
10
11#include "FormatManager.h"
12
13#include <new>
14
15#include <stdio.h>
16#include <string.h>
17
18#include <Autolock.h>
19
20#include "MediaDebug.h"
21
22
23#define TIMEOUT	5000000LL
24	// 5 seconds timeout for sending the reply
25	// TODO: do we really want to pause the server looper for this?
26	//	would be better to offload this action to a second thread
27
28
29#if 0
30static const char*
31family_to_string(media_format_family family)
32{
33	switch (family) {
34		case B_ANY_FORMAT_FAMILY:
35			return "any";
36		case B_BEOS_FORMAT_FAMILY:
37			return "BeOS";
38		case B_QUICKTIME_FORMAT_FAMILY:
39			return "Quicktime";
40		case B_AVI_FORMAT_FAMILY:
41			return "AVI";
42		case B_ASF_FORMAT_FAMILY:
43			return "ASF";
44		case B_MPEG_FORMAT_FAMILY:
45			return "MPEG";
46		case B_WAV_FORMAT_FAMILY:
47			return "WAV";
48		case B_AIFF_FORMAT_FAMILY:
49			return "AIFF";
50		case B_AVR_FORMAT_FAMILY:
51			return "AVR";
52		case B_MISC_FORMAT_FAMILY:
53			return "misc";
54		default:
55			return "unknown";
56	}
57}
58
59
60static const char*
61string_for_description(const media_format_description& desc, char* string,
62	size_t length)
63{
64	switch (desc.family) {
65		case B_ANY_FORMAT_FAMILY:
66			snprintf(string, length, "any format");
67			break;
68		case B_BEOS_FORMAT_FAMILY:
69			snprintf(string, length, "BeOS format, format id 0x%lx",
70				desc.u.beos.format);
71			break;
72		case B_QUICKTIME_FORMAT_FAMILY:
73			snprintf(string, length, "Quicktime format, vendor id 0x%lx, "
74				"codec id 0x%lx", desc.u.quicktime.vendor,
75				desc.u.quicktime.codec);
76			break;
77		case B_AVI_FORMAT_FAMILY:
78			snprintf(string, length, "AVI format, codec id 0x%lx",
79				desc.u.avi.codec);
80			break;
81		case B_ASF_FORMAT_FAMILY:
82			snprintf(string, length, "ASF format, GUID %02x %02x %02x %02x "
83				"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
84				desc.u.asf.guid.data[0], desc.u.asf.guid.data[1],
85				desc.u.asf.guid.data[2], desc.u.asf.guid.data[3],
86				desc.u.asf.guid.data[4], desc.u.asf.guid.data[5],
87				desc.u.asf.guid.data[6], desc.u.asf.guid.data[7],
88				desc.u.asf.guid.data[8], desc.u.asf.guid.data[9],
89				desc.u.asf.guid.data[10], desc.u.asf.guid.data[11],
90				desc.u.asf.guid.data[12], desc.u.asf.guid.data[13],
91				desc.u.asf.guid.data[14], desc.u.asf.guid.data[15]);
92			break;
93		case B_MPEG_FORMAT_FAMILY:
94			snprintf(string, length, "MPEG format, id 0x%lx", desc.u.mpeg.id);
95			break;
96		case B_WAV_FORMAT_FAMILY:
97			snprintf(string, length, "WAV format, codec id 0x%lx",
98				desc.u.wav.codec);
99			break;
100		case B_AIFF_FORMAT_FAMILY:
101			snprintf(string, length, "AIFF format, codec id 0x%lx",
102				desc.u.aiff.codec);
103			break;
104		case B_AVR_FORMAT_FAMILY:
105			snprintf(string, length, "AVR format, id 0x%lx", desc.u.avr.id);
106			break;
107		case B_MISC_FORMAT_FAMILY:
108			snprintf(string, length, "misc format, file-format id 0x%lx, "
109				"codec id 0x%lx", desc.u.misc.file_format, desc.u.misc.codec);
110			break;
111		default:
112			snprintf(string, length, "unknown format");
113			break;
114	}
115	return string;
116}
117#endif
118
119
120// #pragma mark -
121
122
123FormatManager::FormatManager()
124	:
125	fLock("format manager"),
126	fLastUpdate(0),
127	fNextCodecID(1000)
128{
129}
130
131
132pthread_once_t FormatManager::sInitOnce = PTHREAD_ONCE_INIT;
133FormatManager* FormatManager::sInstance = NULL;
134
135
136/* static */ void
137FormatManager::CreateInstance()
138{
139	sInstance = new FormatManager();
140}
141
142
143/* static */ FormatManager*
144FormatManager::GetInstance()
145{
146	pthread_once(&sInitOnce, &CreateInstance);
147
148	return sInstance;
149}
150
151
152
153
154FormatManager::~FormatManager()
155{
156}
157
158
159/*! This method is called when BMediaFormats asks for any updates
160 	made to our format list.
161	If there were any changes since the last time, the whole
162	list will be sent back.
163*/
164void
165FormatManager::GetFormats(bigtime_t lastUpdate, BMessage& reply)
166{
167	BAutolock locker(fLock);
168
169	if (lastUpdate >= fLastUpdate) {
170		// There weren't any changes since last time.
171		reply.AddBool("need_update", false);
172
173		return;
174	}
175
176	// Add all meta formats to the list
177	reply.AddBool("need_update", true);
178	reply.AddInt64("timestamp", system_time());
179
180	int32 count = fList.CountItems();
181	for (int32 i = 0; i < count; i++) {
182		meta_format* format = fList.ItemAt(i);
183		reply.AddData("formats", MEDIA_META_FORMAT_TYPE, format,
184			sizeof(meta_format));
185	}
186}
187
188
189status_t
190FormatManager::MakeFormatFor(const media_format_description* descriptions,
191	int32 descriptionCount, media_format& format, uint32 flags, void* _reserved)
192{
193	BAutolock locker(fLock);
194
195	int codec = fNextCodecID;
196	switch (format.type) {
197		case B_MEDIA_RAW_AUDIO:
198		case B_MEDIA_RAW_VIDEO:
199			// no marker
200			break;
201		case B_MEDIA_ENCODED_AUDIO:
202			if (format.u.encoded_audio.encoding == 0) {
203				format.u.encoded_audio.encoding
204					= (media_encoded_audio_format::audio_encoding)
205						fNextCodecID++;
206			} else {
207				UNIMPLEMENTED();
208				// TODO: Check the encoding and the format passed in for
209				// compatibility and return B_MISMATCHED_VALUES if incompatible
210				// or perhaps something else based on flags?
211			}
212			break;
213		case B_MEDIA_ENCODED_VIDEO:
214			if (format.u.encoded_video.encoding == 0) {
215				format.u.encoded_video.encoding
216					= (media_encoded_video_format::video_encoding)
217						fNextCodecID++;
218			} else {
219				UNIMPLEMENTED();
220				// TODO: Check the encoding and the format passed in for
221				// compatibility and return B_MISMATCHED_VALUES if incompatible
222				// or perhaps something else based on flags?
223			}
224			break;
225		case B_MEDIA_MULTISTREAM:
226			if (format.u.multistream.format == 0) {
227				format.u.multistream.format = fNextCodecID++;
228			} else {
229				UNIMPLEMENTED();
230				// TODO: Check the encoding and the format passed in for
231				// compatibility and return B_MISMATCHED_VALUES if incompatible
232				// or perhaps something else based on flags?
233			}
234			break;
235		default:
236			// nothing to do
237			return B_OK;
238	}
239	fLastUpdate = system_time();
240
241	status_t result = B_OK;
242	// TODO: Support "flags" (B_SET_DEFAULT, B_EXCLUSIVE, B_NO_MERGE)!
243	for (int32 i = 0; i < descriptionCount; i++) {
244		meta_format* metaFormat = new(std::nothrow) meta_format(
245			descriptions[i], format, codec);
246		if (metaFormat == NULL
247			|| !fList.BinaryInsert(metaFormat, meta_format::Compare)) {
248			delete metaFormat;
249			result = B_NO_MEMORY;
250			break;
251		}
252	}
253
254	return result;
255}
256
257
258void
259FormatManager::RemoveFormat(const media_format& format)
260{
261	BAutolock locker(fLock);
262
263	int32 foundIndex = -1;
264	for (int32 i = fList.CountItems() - 1; i >= 0; i--) {
265		meta_format* metaFormat = fList.ItemAt(i);
266		if (metaFormat->format == format) {
267			if (foundIndex != -1) {
268				printf("FormatManager::RemoveFormat() - format already "
269					"present at previous index: %" B_PRId32 "\n", foundIndex);
270			}
271			foundIndex = i;
272		}
273	}
274
275	if (foundIndex >= 0)
276		delete fList.RemoveItemAt(foundIndex);
277	else
278		printf("FormatManager::RemoveFormat() - format not found!\n");
279
280	fLastUpdate = system_time();
281}
282