⛏️ index : haiku.git

/*
 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
 * Copyright 2002-2004, Marcus Overhagen <marcus@overhagen.de>
 * All rights reserved. Distributed under the terms of the MIT license.
 */

#include <MediaFile.h>

#include <new>

#include <stdlib.h>
#include <string.h>

#include <File.h>
#include <MediaTrack.h>
#include <Url.h>

#include "MediaDebug.h"

#include "MediaExtractor.h"
#include "MediaStreamer.h"
#include "MediaWriter.h"


BMediaFile::BMediaFile(const entry_ref* ref)
{
	CALLED();
	_Init();
	fDeleteSource = true;
	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));
}


BMediaFile::BMediaFile(BDataIO* source)
{
	CALLED();
	_Init();
	_InitReader(source);
}


BMediaFile::BMediaFile(const entry_ref* ref, int32 flags)
{
	CALLED();
	_Init();
	fDeleteSource = true;
	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY), NULL, flags);
}


BMediaFile::BMediaFile(BDataIO* source, int32 flags)
{
	CALLED();
	_Init();
	_InitReader(source, NULL, flags);
}


BMediaFile::BMediaFile(const entry_ref* ref, const media_file_format* mfi,
	int32 flags)
{
	CALLED();
	_Init();
	fDeleteSource = true;
	_InitWriter(new(std::nothrow) BFile(ref, B_CREATE_FILE | B_ERASE_FILE
		| B_WRITE_ONLY), NULL, mfi, flags);
}


BMediaFile::BMediaFile(BDataIO* destination, const media_file_format* mfi,
	int32 flags)
{
	CALLED();
	_Init();
	_InitWriter(destination, NULL, mfi, flags);
}


// File will be set later by SetTo()
BMediaFile::BMediaFile(const media_file_format* mfi, int32 flags)
{
	debugger("BMediaFile::BMediaFile not implemented");
}


BMediaFile::BMediaFile(const BUrl& url)
{
	CALLED();
	_Init();
	fDeleteSource = true;
	_InitReader(NULL, &url);
}


BMediaFile::BMediaFile(const BUrl& url, int32 flags)
{
	CALLED();
	_Init();
	fDeleteSource = true;
	_InitReader(NULL, &url, flags);
}


BMediaFile::BMediaFile(const BUrl& destination, const media_file_format* mfi,
	int32 flags)
{
	CALLED();
	_Init();
	fDeleteSource = true;
	_InitWriter(NULL, &destination, mfi, flags);
	// TODO: Implement streaming server support, it's
	// a pretty complex thing compared to client mode
	// and will require to expand the current BMediaFile
	// design to be aware of it.
}


status_t
BMediaFile::SetTo(const entry_ref* ref)
{
	CALLED();

	if (ref == NULL)
		return B_BAD_VALUE;

	_UnInit();
	fDeleteSource = true;
	_InitReader(new(std::nothrow) BFile(ref, O_RDONLY));

	return fErr;
}


status_t
BMediaFile::SetTo(BDataIO* destination)
{
	CALLED();

	if (destination == NULL)
		return B_BAD_VALUE;

	_UnInit();
	_InitReader(destination);

	return fErr;
}


status_t
BMediaFile::SetTo(const BUrl& url)
{
	CALLED();

	_UnInit();
	_InitReader(NULL, &url);

	return fErr;
}


BMediaFile::~BMediaFile()
{
	CALLED();

	_UnInit();
}


status_t
BMediaFile::InitCheck() const
{
	CALLED();
	return fErr;
}


status_t
BMediaFile::GetFileFormatInfo(media_file_format* mfi) const
{
	CALLED();
	if (mfi == NULL)
		return B_BAD_VALUE;
	if (fErr)
		return B_ERROR;
	*mfi = fMFI;
	return B_OK;
}


status_t
BMediaFile::GetMetaData(BMessage* _data) const
{
	if (fExtractor == NULL)
		return B_NO_INIT;
	if (_data == NULL)
		return B_BAD_VALUE;

	_data->MakeEmpty();

	return fExtractor->GetMetaData(_data);
}


const char*
BMediaFile::Copyright() const
{
	return fExtractor->Copyright();
}


int32
BMediaFile::CountTracks() const
{
	return fTrackNum;
}


// Can be called multiple times with the same index.  You must call
// ReleaseTrack() when you're done with a track.
BMediaTrack*
BMediaFile::TrackAt(int32 index)
{
	CALLED();
	if (fTrackList == NULL || fExtractor == NULL
		|| index < 0 || index >= fTrackNum) {
		return NULL;
	}
	if (fTrackList[index] == NULL) {
		TRACE("BMediaFile::TrackAt, creating new track for index %"
			B_PRId32 "\n", index);
		fTrackList[index] = new(std::nothrow) BMediaTrack(fExtractor, index);
		TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]);
	}
	return fTrackList[index];
}


// Release the resource used by a given BMediaTrack object, to reduce
// the memory usage of your application. The specific 'track' object
// can no longer be used, but you can create another one by calling
// TrackAt() with the same track index.
status_t
BMediaFile::ReleaseTrack(BMediaTrack* track)
{
	CALLED();
	if (!fTrackList || !track)
		return B_ERROR;
	for (int32 i = 0; i < fTrackNum; i++) {
		if (fTrackList[i] == track) {
			TRACE("BMediaFile::ReleaseTrack, releasing track %p with index "
				"%" B_PRId32 "\n", track, i);
			delete track;
			fTrackList[i] = NULL;
			return B_OK;
		}
	}
	fprintf(stderr, "BMediaFile::ReleaseTrack track %p not found\n", track);
	return B_ERROR;
}


status_t
BMediaFile::ReleaseAllTracks()
{
	CALLED();
	if (!fTrackList)
		return B_ERROR;
	for (int32 i = 0; i < fTrackNum; i++) {
		if (fTrackList[i]) {
			TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with "
				"index %" B_PRId32 "\n", fTrackList[i], i);
			delete fTrackList[i];
			fTrackList[i] = NULL;
		}
	}
	return B_OK;
}


// Create and add a track to the media file
BMediaTrack*
BMediaFile::CreateTrack(media_format* mediaFormat,
	const media_codec_info* codecInfo, uint32 flags)
{
	if (mediaFormat == NULL)
		return NULL;

	// NOTE: It is allowed to pass NULL for codecInfo. In that case, the
	// track won't have an Encoder and you can only use WriteChunk() with
	// already encoded data.

	// Make room for the new track.
	BMediaTrack** trackList = (BMediaTrack**)realloc(fTrackList,
		(fTrackNum + 1) * sizeof(BMediaTrack*));
	if (trackList == NULL)
		return NULL;

	int32 streamIndex = fTrackNum;
	fTrackList = trackList;
	fTrackNum += 1;

	BMediaTrack* track = new(std::nothrow) BMediaTrack(fWriter, streamIndex,
		mediaFormat, codecInfo);

	fTrackList[streamIndex] = track;

	return track;
}


// Create and add a raw track to the media file (it has no encoder)
BMediaTrack*
BMediaFile::CreateTrack(media_format* mf, uint32 flags)
{
	return CreateTrack(mf, NULL, flags);
}


// For BeOS R5 compatibility
extern "C" BMediaTrack*
CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(
	BMediaFile* self, media_format* mf, const media_codec_info* mci);
BMediaTrack*
CreateTrack__10BMediaFileP12media_formatPC16media_codec_info(BMediaFile* self,
	media_format* mf, const media_codec_info* mci)
{
	return self->CreateTrack(mf, mci, 0);
}


// For BeOS R5 compatibility
extern "C" BMediaTrack* CreateTrack__10BMediaFileP12media_format(
	BMediaFile* self, media_format* mf);
BMediaTrack*
CreateTrack__10BMediaFileP12media_format(BMediaFile* self, media_format* mf)
{
	return self->CreateTrack(mf, NULL, 0);
}


// Lets you set the copyright info for the entire file
status_t
BMediaFile::AddCopyright(const char* copyright)
{
	if (fWriter == NULL)
		return B_NO_INIT;

	return fWriter->SetCopyright(copyright);
}


// Call this to add user-defined chunks to a file (if they're supported)
status_t
BMediaFile::AddChunk(int32 type, const void* data, size_t size)
{
	UNIMPLEMENTED();
	return B_OK;
}


// After you have added all the tracks you want, call this
status_t
BMediaFile::CommitHeader()
{
	if (fWriter == NULL)
		return B_NO_INIT;

	return fWriter->CommitHeader();
}


// After you have written all the data to the track objects, call this
status_t
BMediaFile::CloseFile()
{
	if (fWriter == NULL)
		return B_NO_INIT;

	return fWriter->Close();
}

// This is for controlling file format parameters

// returns a copy of the parameter web
status_t
BMediaFile::GetParameterWeb(BParameterWeb** outWeb)
{
	UNIMPLEMENTED();
	return B_ERROR;
}


// deprecated BeOS R5 API
BParameterWeb*
BMediaFile::Web()
{
	UNIMPLEMENTED();
	return 0;
}


status_t
BMediaFile::GetParameterValue(int32 id,	void* value, size_t* size)
{
	UNIMPLEMENTED();
	return B_OK;
}


status_t
BMediaFile::SetParameterValue(int32 id,	const void* value, size_t size)
{
	UNIMPLEMENTED();
	return B_OK;
}


BView*
BMediaFile::GetParameterView()
{
	UNIMPLEMENTED();
	return 0;
}


status_t
BMediaFile::Perform(int32 selector, void* data)
{
	UNIMPLEMENTED();
	return B_OK;
}


status_t
BMediaFile::ControlFile(int32 selector, void* ioData, size_t size)
{
	UNIMPLEMENTED();
	return B_ERROR;
}


// #pragma mark - private


void
BMediaFile::_Init()
{
	CALLED();

	fSource = NULL;
	fTrackNum = 0;
	fTrackList = NULL;
	fExtractor = NULL;
	fStreamer = NULL;
	fWriter = NULL;
	fWriterID = 0;
	fErr = B_OK;
	fDeleteSource = false;

	// not used so far:
	fEncoderMgr = NULL;
	fWriterMgr = NULL;
	fFileClosed = false;
}


void
BMediaFile::_UnInit()
{
	ReleaseAllTracks();
	free(fTrackList);
	fTrackList = NULL;
	fTrackNum = 0;

	// Tells the extractor to stop its asynchronous processing
	// before deleting its source
	if (fExtractor != NULL)
		fExtractor->StopProcessing();

	if (fDeleteSource) {
		delete fSource;
		fDeleteSource = false;
	}
	fSource = NULL;

	// Deleting the extractor or writer can cause unloading of the plugins.
	// The source must be deleted before that, because it can come from a
	// plugin (for example the http_streamer)
	delete fExtractor;
	fExtractor = NULL;
	delete fWriter;
	fWriter = NULL;
	delete fStreamer;
	fStreamer = NULL;
}


void
BMediaFile::_InitReader(BDataIO* source, const BUrl* url, int32 flags)
{
	CALLED();

	if (source == NULL && url == NULL) {
		fErr = B_NO_MEMORY;
		return;
	}

	if (source == NULL)
		_InitStreamer(*url, &source);
	else if (BFile* file = dynamic_cast<BFile*>(source))
		fErr = file->InitCheck();

	if (fErr != B_OK)
		return;

	fExtractor = new(std::nothrow) MediaExtractor(source, flags);

	if (fExtractor == NULL)
		fErr = B_NO_MEMORY;
	else
		fErr = fExtractor->InitCheck();

	if (fErr != B_OK)
		return;

	fSource = source;

	fExtractor->GetFileFormatInfo(&fMFI);
	fTrackNum = fExtractor->StreamCount();
	fTrackList = (BMediaTrack**)malloc(fTrackNum * sizeof(BMediaTrack*));
	if (fTrackList == NULL) {
		fErr = B_NO_MEMORY;
		return;
	}
	memset(fTrackList, 0, fTrackNum * sizeof(BMediaTrack*));
}


void
BMediaFile::_InitWriter(BDataIO* target, const BUrl* url,
	const media_file_format* fileFormat, int32 flags)
{
	CALLED();

	if (fileFormat == NULL) {
		fErr = B_BAD_VALUE;
		return;
	}

	if (target == NULL && url == NULL) {
		fErr = B_NO_MEMORY;
		return;
	}

	fMFI = *fileFormat;

	if (target == NULL) {
		_InitStreamer(*url, &target);
		if (fErr != B_OK)
			return;
	}

	fWriter = new(std::nothrow) MediaWriter(target, fMFI);

	if (fWriter == NULL)
		fErr = B_NO_MEMORY;
	else
		fErr = fWriter->InitCheck();
	if (fErr != B_OK)
		return;

	// Get the actual source from the writer
	fSource = fWriter->Target();
	fTrackNum = 0;
}


void
BMediaFile::_InitStreamer(const BUrl& url, BDataIO** adapter)
{
	if (fStreamer != NULL)
		delete fStreamer;

	TRACE(url.UrlString());

	fStreamer = new(std::nothrow) MediaStreamer(url);
	if (fStreamer == NULL) {
		fErr = B_NO_MEMORY;
		return;
	}

	fErr = fStreamer->CreateAdapter(adapter);
}

/*
//unimplemented
BMediaFile::BMediaFile();
BMediaFile::BMediaFile(const BMediaFile&);
 BMediaFile::BMediaFile& operator=(const BMediaFile&);
*/

status_t BMediaFile::_Reserved_BMediaFile_0(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_1(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_2(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_3(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_4(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_5(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_6(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_7(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_8(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_9(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_10(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_11(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_12(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_13(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_14(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_15(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_16(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_17(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_18(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_19(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_20(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_21(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_22(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_23(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_24(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_25(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_26(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_27(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_28(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_29(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_30(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_31(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_32(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_33(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_34(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_35(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_36(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_37(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_38(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_39(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_40(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_41(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_42(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_43(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_44(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_45(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_46(int32 arg, ...) { return B_ERROR; }
status_t BMediaFile::_Reserved_BMediaFile_47(int32 arg, ...) { return B_ERROR; }