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