xref: /haiku/src/kits/media/FormatManager.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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
30 static const char*
31 family_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 
60 static const char*
61 string_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 
123 FormatManager::FormatManager()
124 	:
125 	fLock("format manager"),
126 	fLastUpdate(0),
127 	fNextCodecID(1000)
128 {
129 }
130 
131 
132 pthread_once_t FormatManager::sInitOnce = PTHREAD_ONCE_INIT;
133 FormatManager* FormatManager::sInstance = NULL;
134 
135 
136 /* static */ void
137 FormatManager::CreateInstance()
138 {
139 	sInstance = new FormatManager();
140 }
141 
142 
143 /* static */ FormatManager*
144 FormatManager::GetInstance()
145 {
146 	pthread_once(&sInitOnce, &CreateInstance);
147 
148 	return sInstance;
149 }
150 
151 
152 
153 
154 FormatManager::~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 */
164 void
165 FormatManager::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 
189 status_t
190 FormatManager::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 
258 void
259 FormatManager::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