/*
 * Copyright 2015, Dario Casalinuovo
 * Copyright 2010, Oleg Krysenkov, beos344@mail.ru.
 * Copyright 2012, Fredrik Modéen, [firstname]@[lastname].se.
 * Copyright 2004-2007, Marcus Overhagen. All rights reserved.
 * Distributed under the terms of the MIT License.
 */
 
 
#include <MediaEncoder.h>
 
#include <EncoderPlugin.h>
#include <PluginManager.h>
 
#include <new>
 
#include "MediaDebug.h"
 
/*************************************************************
 * public BMediaEncoder
 *************************************************************/
 
BMediaEncoder::BMediaEncoder()
	:
	fEncoder(NULL),
	fInitStatus(B_NO_INIT)
{
	CALLED();
}
 
 
BMediaEncoder::BMediaEncoder(const media_format* outputFormat)
	:
	fEncoder(NULL),
	fInitStatus(B_NO_INIT)
{
	CALLED();
	SetTo(outputFormat);
}
 
 
BMediaEncoder::BMediaEncoder(const media_codec_info* mci)
	:
	fEncoder(NULL),
	fInitStatus(B_NO_INIT)
{
	CALLED();
	SetTo(mci);
}
 
 
/* virtual */
BMediaEncoder::~BMediaEncoder()
{
	CALLED();
	ReleaseEncoder();
}
 
 
status_t 
BMediaEncoder::InitCheck() const
{
	return fInitStatus;
}
 
 
status_t 
BMediaEncoder::SetTo(const media_format* outputFormat)
{
	CALLED();
 
	status_t err = B_ERROR;
	ReleaseEncoder();
 
	if (outputFormat == NULL)
		return fInitStatus;
 
	media_format format = *outputFormat;
	err = gPluginManager.CreateEncoder(&fEncoder, format);
	if (fEncoder != NULL && err == B_OK) {
		err = _AttachToEncoder();
		if (err == B_OK)
			return err;
	}
	ReleaseEncoder();
	fInitStatus = err;
	return err;
}
 
 
status_t 
BMediaEncoder::SetTo(const media_codec_info* mci)
{
	CALLED();
 
	ReleaseEncoder();
	status_t err = gPluginManager.CreateEncoder(&fEncoder, mci, 0);
	if (fEncoder != NULL && err == B_OK) {
		err = _AttachToEncoder();
		if (err == B_OK) {
			fInitStatus = B_OK;
			return B_OK;
		}
	}
 
	ReleaseEncoder();
	fInitStatus = err;
	return err;
}
 
 
status_t 
BMediaEncoder::SetFormat(media_format* inputFormat,
	media_format* outputFormat, media_file_format* mfi)
{
	CALLED();
	TRACE("BMediaEncoder::SetFormat. Input = %d, Output = %d\n",
		inputFormat->type, outputFormat->type);
 
	if (!fEncoder)
		return B_NO_INIT;
 
	if (outputFormat != NULL)
		SetTo(outputFormat);
 
	//TODO: How we support mfi?
	return fEncoder->SetUp(inputFormat);
}
 
 
status_t 
BMediaEncoder::Encode(const void* buffer,
	int64 frameCount, media_encode_info* info)
{
	CALLED();
 
	if (!fEncoder)
		return B_NO_INIT;
 
	return fEncoder->Encode(buffer, frameCount, info);
}
 
 
status_t 
BMediaEncoder::GetEncodeParameters(encode_parameters* parameters) const
{
	CALLED();
 
	if (fEncoder == NULL)
		return B_NO_INIT;
 
	return fEncoder->GetEncodeParameters(parameters);
}
 
 
status_t 
BMediaEncoder::SetEncodeParameters(encode_parameters* parameters)
{
	CALLED();
 
	if (fEncoder == NULL)
		return B_NO_INIT;
 
	return fEncoder->SetEncodeParameters(parameters);
}
 
 
/*************************************************************
 * protected BMediaEncoder
 *************************************************************/
 
/* virtual */ status_t 
BMediaEncoder::AddTrackInfo(uint32 code, const char* data, size_t size)
{
	CALLED();
 
	if (fEncoder == NULL)
		return B_NO_INIT;
 
	return fEncoder->AddTrackInfo(code, data, size);
}
 
 
/*************************************************************
 * private BMediaEncoder
 *************************************************************/
 
/*
//	unimplemented
BMediaEncoder::BMediaEncoder(const BMediaEncoder &);
BMediaEncoder::BMediaEncoder & operator=(const BMediaEncoder &);
*/
 
/* static */ status_t 
BMediaEncoder::write_chunk(void* classptr, const void* chunk_data,
	size_t chunk_len, media_encode_info* info)
{
	CALLED();
 
	BMediaEncoder* encoder = static_cast<BMediaEncoder*>(classptr);
	if (encoder == NULL)
		return B_BAD_VALUE;
	return encoder->WriteChunk(chunk_data, chunk_len, info);
}
 
 
void
BMediaEncoder::Init()
{
	UNIMPLEMENTED();
}
 
 
void 
BMediaEncoder::ReleaseEncoder()
{
	CALLED();
	if (fEncoder != NULL) {
		gPluginManager.DestroyEncoder(fEncoder);
		fEncoder = NULL;
	}
	fInitStatus = B_NO_INIT;
}
 
 
status_t
BMediaEncoder::_AttachToEncoder()
{
	class MediaEncoderChunkWriter : public ChunkWriter {
		public:
			MediaEncoderChunkWriter(BMediaEncoder* encoder)
			{
				fEncoder = encoder;
			}
			virtual status_t WriteChunk(const void* chunkBuffer,
				size_t chunkSize, media_encode_info* encodeInfo)
			{
				return fEncoder->WriteChunk(chunkBuffer, chunkSize, encodeInfo);
			}
		private:
			BMediaEncoder* fEncoder;
	} *writer = new(std::nothrow) MediaEncoderChunkWriter(this);
 
	if (!writer)
		return B_NO_MEMORY;
 
	fEncoder->SetChunkWriter(writer);
	return B_OK;
}
 
 
status_t BMediaEncoder::_Reserved_BMediaEncoder_0(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_1(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_2(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_3(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_4(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_5(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_6(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_7(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_8(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_9(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_10(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_11(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_12(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_13(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_14(int32 arg, ...) { return B_ERROR; }
status_t BMediaEncoder::_Reserved_BMediaEncoder_15(int32 arg, ...) { return B_ERROR; }
 
/*************************************************************
 * public BMediaBufferEncoder
 *************************************************************/
 
BMediaBufferEncoder::BMediaBufferEncoder()
	:
	BMediaEncoder(),
	fBuffer(NULL)
{
	CALLED();
}
 
 
BMediaBufferEncoder::BMediaBufferEncoder(const media_format* outputFormat)
	:
	BMediaEncoder(outputFormat),
	fBuffer(NULL)
{
	CALLED();
}
 
 
BMediaBufferEncoder::BMediaBufferEncoder(const media_codec_info* mci)
	:
	BMediaEncoder(mci),
	fBuffer(NULL)
{
	CALLED();
}
 
 
status_t
BMediaBufferEncoder::EncodeToBuffer(void* outputBuffer,
	size_t* outputSize, const void* inputBuffer,
	int64 frameCount, media_encode_info* info)
{
	CALLED();
 
	status_t error;
	fBuffer = outputBuffer;
	fBufferSize = *outputSize;
	error = Encode(inputBuffer, frameCount, info);
	if (fBuffer) {
		fBuffer = NULL;
		*outputSize = 0;
	} else {
		*outputSize = fBufferSize;
	}
	return error;
}
 
 
/*************************************************************
 * public BMediaBufferEncoder
 *************************************************************/
 
status_t
BMediaBufferEncoder::WriteChunk(const void* chunkData,
	size_t chunkLen, media_encode_info* info)
{
	CALLED();
 
	if (fBuffer == NULL)
		return B_ENTRY_NOT_FOUND;
 
	if (chunkLen > (size_t)fBufferSize) {
		memcpy(fBuffer, chunkData, fBufferSize);
		fBuffer = NULL;
		return B_DEVICE_FULL;
	}
 
	memcpy(fBuffer, chunkData, chunkLen);
	fBufferSize = chunkLen;
	fBuffer = NULL;
	return B_NO_ERROR;
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fBufferSize.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fBufferSize.

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fBufferSize.