/*
 * Copyright 2004-2009, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT license.
 *
 * Authors:
 *		Axel Dörfler
 *		Marcus Overhagen
 */
 
 
#include "FormatManager.h"
 
#include <new>
 
#include <stdio.h>
#include <string.h>
 
#include <Autolock.h>
 
#include "MediaDebug.h"
 
 
#define TIMEOUT	5000000LL
	// 5 seconds timeout for sending the reply
	// TODO: do we really want to pause the server looper for this?
	//	would be better to offload this action to a second thread
 
 
#if 0
static const char*
family_to_string(media_format_family family)
{
	switch (family) {
		case B_ANY_FORMAT_FAMILY:
			return "any";
		case B_BEOS_FORMAT_FAMILY:
			return "BeOS";
		case B_QUICKTIME_FORMAT_FAMILY:
			return "Quicktime";
		case B_AVI_FORMAT_FAMILY:
			return "AVI";
		case B_ASF_FORMAT_FAMILY:
			return "ASF";
		case B_MPEG_FORMAT_FAMILY:
			return "MPEG";
		case B_WAV_FORMAT_FAMILY:
			return "WAV";
		case B_AIFF_FORMAT_FAMILY:
			return "AIFF";
		case B_AVR_FORMAT_FAMILY:
			return "AVR";
		case B_MISC_FORMAT_FAMILY:
			return "misc";
		default:
			return "unknown";
	}
}
 
 
static const char*
string_for_description(const media_format_description& desc, char* string,
	size_t length)
{
	switch (desc.family) {
		case B_ANY_FORMAT_FAMILY:
			snprintf(string, length, "any format");
			break;
		case B_BEOS_FORMAT_FAMILY:
			snprintf(string, length, "BeOS format, format id 0x%lx",
				desc.u.beos.format);
			break;
		case B_QUICKTIME_FORMAT_FAMILY:
			snprintf(string, length, "Quicktime format, vendor id 0x%lx, "
				"codec id 0x%lx", desc.u.quicktime.vendor,
				desc.u.quicktime.codec);
			break;
		case B_AVI_FORMAT_FAMILY:
			snprintf(string, length, "AVI format, codec id 0x%lx",
				desc.u.avi.codec);
			break;
		case B_ASF_FORMAT_FAMILY:
			snprintf(string, length, "ASF format, GUID %02x %02x %02x %02x "
				"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
				desc.u.asf.guid.data[0], desc.u.asf.guid.data[1],
				desc.u.asf.guid.data[2], desc.u.asf.guid.data[3],
				desc.u.asf.guid.data[4], desc.u.asf.guid.data[5],
				desc.u.asf.guid.data[6], desc.u.asf.guid.data[7],
				desc.u.asf.guid.data[8], desc.u.asf.guid.data[9],
				desc.u.asf.guid.data[10], desc.u.asf.guid.data[11],
				desc.u.asf.guid.data[12], desc.u.asf.guid.data[13],
				desc.u.asf.guid.data[14], desc.u.asf.guid.data[15]);
			break;
		case B_MPEG_FORMAT_FAMILY:
			snprintf(string, length, "MPEG format, id 0x%lx", desc.u.mpeg.id);
			break;
		case B_WAV_FORMAT_FAMILY:
			snprintf(string, length, "WAV format, codec id 0x%lx",
				desc.u.wav.codec);
			break;
		case B_AIFF_FORMAT_FAMILY:
			snprintf(string, length, "AIFF format, codec id 0x%lx",
				desc.u.aiff.codec);
			break;
		case B_AVR_FORMAT_FAMILY:
			snprintf(string, length, "AVR format, id 0x%lx", desc.u.avr.id);
			break;
		case B_MISC_FORMAT_FAMILY:
			snprintf(string, length, "misc format, file-format id 0x%lx, "
				"codec id 0x%lx", desc.u.misc.file_format, desc.u.misc.codec);
			break;
		default:
			snprintf(string, length, "unknown format");
			break;
	}
	return string;
}
#endif
 
 
// #pragma mark -
 
 
FormatManager::FormatManager()
	:
	fLock("format manager"),
	fLastUpdate(0),
	fNextCodecID(1000)
{
}
 
 
pthread_once_t FormatManager::sInitOnce = PTHREAD_ONCE_INIT;
FormatManager* FormatManager::sInstance = NULL;
 
 
/* static */ void
FormatManager::CreateInstance()
{
	sInstance = new FormatManager();
}
 
 
/* static */ FormatManager*
FormatManager::GetInstance()
{
	pthread_once(&sInitOnce, &CreateInstance);
 
	return sInstance;
}
 
 
 
 
FormatManager::~FormatManager()
{
}
 
 
/*! This method is called when BMediaFormats asks for any updates
 	made to our format list.
	If there were any changes since the last time, the whole
	list will be sent back.
*/
void
FormatManager::GetFormats(bigtime_t lastUpdate, BMessage& reply)
{
	BAutolock locker(fLock);
 
	if (lastUpdate >= fLastUpdate) {
		// There weren't any changes since last time.
		reply.AddBool("need_update", false);
 
		return;
	}
 
	// Add all meta formats to the list
	reply.AddBool("need_update", true);
	reply.AddInt64("timestamp", system_time());
 
	int32 count = fList.CountItems();
	for (int32 i = 0; i < count; i++) {
		meta_format* format = fList.ItemAt(i);
		reply.AddData("formats", MEDIA_META_FORMAT_TYPE, format,
			sizeof(meta_format));
	}
}
 
 
status_t
FormatManager::MakeFormatFor(const media_format_description* descriptions,
	int32 descriptionCount, media_format& format, uint32 flags, void* _reserved)
{
	BAutolock locker(fLock);
 
	int codec = fNextCodecID;
	switch (format.type) {
		case B_MEDIA_RAW_AUDIO:
		case B_MEDIA_RAW_VIDEO:
			// no marker
			break;
		case B_MEDIA_ENCODED_AUDIO:
			if (format.u.encoded_audio.encoding == 0) {
				format.u.encoded_audio.encoding
					= (media_encoded_audio_format::audio_encoding)
						fNextCodecID++;
			} else {
				UNIMPLEMENTED();
				// TODO: Check the encoding and the format passed in for
				// compatibility and return B_MISMATCHED_VALUES if incompatible
				// or perhaps something else based on flags?
			}
			break;
		case B_MEDIA_ENCODED_VIDEO:
			if (format.u.encoded_video.encoding == 0) {
				format.u.encoded_video.encoding
					= (media_encoded_video_format::video_encoding)
						fNextCodecID++;
			} else {
				UNIMPLEMENTED();
				// TODO: Check the encoding and the format passed in for
				// compatibility and return B_MISMATCHED_VALUES if incompatible
				// or perhaps something else based on flags?
			}
			break;
		case B_MEDIA_MULTISTREAM:
			if (format.u.multistream.format == 0) {
				format.u.multistream.format = fNextCodecID++;
			} else {
				UNIMPLEMENTED();
				// TODO: Check the encoding and the format passed in for
				// compatibility and return B_MISMATCHED_VALUES if incompatible
				// or perhaps something else based on flags?
			}
			break;
		default:
			// nothing to do
			return B_OK;
	}
	fLastUpdate = system_time();
 
	status_t result = B_OK;
	// TODO: Support "flags" (B_SET_DEFAULT, B_EXCLUSIVE, B_NO_MERGE)!
	for (int32 i = 0; i < descriptionCount; i++) {
		meta_format* metaFormat = new(std::nothrow) meta_format(
			descriptions[i], format, codec);
		if (metaFormat == NULL
			|| !fList.BinaryInsert(metaFormat, meta_format::Compare)) {
			delete metaFormat;
			result = B_NO_MEMORY;
			break;
		}
	}
 
	return result;
}
 
 
void
FormatManager::RemoveFormat(const media_format& format)
{
	BAutolock locker(fLock);
 
	int32 foundIndex = -1;
	for (int32 i = fList.CountItems() - 1; i >= 0; i--) {
		meta_format* metaFormat = fList.ItemAt(i);
		if (metaFormat->format == format) {
			if (foundIndex != -1) {
				printf("FormatManager::RemoveFormat() - format already "
					"present at previous index: %" B_PRId32 "\n", foundIndex);
			}
			foundIndex = i;
		}
	}
 
	if (foundIndex >= 0)
		delete fList.RemoveItemAt(foundIndex);
	else
		printf("FormatManager::RemoveFormat() - format not found!\n");
 
	fLastUpdate = system_time();
}

V547 Expression 'format.u.encoded_audio.encoding == 0' is always true.

V547 Expression 'format.u.encoded_video.encoding == 0' is always true.