⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 metadata_manip.cpp

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/* test_libFLAC++ - Unit tester for libFLAC++
 * Copyright (C) 2002,2003,2004,2005  Josh Coalson
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

extern "C" {
#include "file_utils.h"
}
#include "FLAC/assert.h"
#include "FLAC++/decoder.h"
#include "FLAC++/metadata.h"
#include "share/grabbag.h"
#include <stdio.h>
#include <stdlib.h> /* for malloc() */
#include <string.h> /* for memcpy()/memset() */

#if defined _MSC_VER || defined __MINGW32__
#include <sys/utime.h> /* for utime() */
#include <io.h> /* for chmod() */
#else
#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
#include <utime.h> /* for utime() */
#include <unistd.h> /* for chown(), unlink() */
#endif
#include <sys/stat.h> /* for stat(), maybe chmod() */

/******************************************************************************
	The general strategy of these tests (for interface levels 1 and 2) is
	to create a dummy FLAC file with a known set of initial metadata
	blocks, then keep a mirror locally of what we expect the metadata to be
	after each operation.  Then testing becomes a simple matter of running
	a FLAC::Decoder::File over the dummy file after each operation, comparing
	the decoded metadata to what's in our local copy.  If there are any
	differences in the metadata, or the actual audio data is corrupted, we
	will catch it while decoding.
******************************************************************************/

class OurFileDecoder: public FLAC::Decoder::File {
public:
	inline OurFileDecoder(bool ignore_metadata): ignore_metadata_(ignore_metadata), error_occurred_(false) { }

	bool ignore_metadata_;
	bool error_occurred_;
protected:
	::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
	void metadata_callback(const ::FLAC__StreamMetadata *metadata);
	void error_callback(::FLAC__StreamDecoderErrorStatus status);
};

struct OurMetadata {
	FLAC::Metadata::Prototype *blocks[64];
	unsigned num_blocks;
};

static const char *flacfile_ = "metadata.flac";

/* our copy of the metadata in flacfile_ */
static OurMetadata our_metadata_;

/* the current block number that corresponds to the position of the iterator we are testing */
static unsigned mc_our_block_number_ = 0;

static bool die_(const char *msg)
{
	printf("ERROR: %s\n", msg);
	return false;
}

static bool die_c_(const char *msg, FLAC::Metadata::Chain::Status status)
{
	printf("ERROR: %s\n", msg);
	printf("       status=%u (%s)\n", (unsigned)((::FLAC__Metadata_ChainStatus)status), status.as_cstring());
	return false;
}

static bool die_ss_(const char *msg, FLAC::Metadata::SimpleIterator &iterator)
{
	const FLAC::Metadata::SimpleIterator::Status status = iterator.status();
	printf("ERROR: %s\n", msg);
	printf("       status=%u (%s)\n", (unsigned)((::FLAC__Metadata_SimpleIteratorStatus)status), status.as_cstring());
	return false;
}

static void *malloc_or_die_(size_t size)
{
	void *x = malloc(size);
	if(0 == x) {
		fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
		exit(1);
	}
	return x;
}

/* functions for working with our metadata copy */

static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
{
	unsigned i;
	FLAC::Metadata::Prototype *obj = block;
	FLAC__ASSERT(position < our_metadata_.num_blocks);
	if(copy) {
		if(0 == (obj = FLAC::Metadata::clone(block)))
			return die_("during FLAC::Metadata::clone()");
	}
	delete our_metadata_.blocks[position];
	our_metadata_.blocks[position] = obj;

	/* set the is_last flags */
	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
		our_metadata_.blocks[i]->set_is_last(false);
	our_metadata_.blocks[i]->set_is_last(true);

	return true;
}

static bool insert_to_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
{
	unsigned i;
	FLAC::Metadata::Prototype *obj = block;
	if(copy) {
		if(0 == (obj = FLAC::Metadata::clone(block)))
			return die_("during FLAC::Metadata::clone()");
	}
	if(position > our_metadata_.num_blocks) {
		position = our_metadata_.num_blocks;
	}
	else {
		for(i = our_metadata_.num_blocks; i > position; i--)
			our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
	}
	our_metadata_.blocks[position] = obj;
	our_metadata_.num_blocks++;

	/* set the is_last flags */
	for(i = 0; i < our_metadata_.num_blocks - 1; i++)
		our_metadata_.blocks[i]->set_is_last(false);
	our_metadata_.blocks[i]->set_is_last(true);

	return true;
}

static void delete_from_our_metadata_(unsigned position)
{
	unsigned i;
	FLAC__ASSERT(position < our_metadata_.num_blocks);
	delete our_metadata_.blocks[position];
	for(i = position; i < our_metadata_.num_blocks - 1; i++)
		our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
	our_metadata_.num_blocks--;

	/* set the is_last flags */
	if(our_metadata_.num_blocks > 0) {
		for(i = 0; i < our_metadata_.num_blocks - 1; i++)
			our_metadata_.blocks[i]->set_is_last(false);
		our_metadata_.blocks[i]->set_is_last(true);
	}
}

void add_to_padding_length_(unsigned index, int delta)
{
	FLAC::Metadata::Padding *padding = dynamic_cast<FLAC::Metadata::Padding *>(our_metadata_.blocks[index]);
	FLAC__ASSERT(0 != padding);
	padding->set_length((unsigned)((int)padding->get_length() + delta));
}

/*
 * This wad of functions supports filename- and callback-based chain reading/writing.
 * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
 */
bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
{
	static const char *tempfile_suffix = ".metadata_edit";

	if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
		return false;
	strcpy(*tempfilename, filename);
	strcat(*tempfilename, tempfile_suffix);

	if(0 == (*tempfile = fopen(*tempfilename, "wb")))
		return false;

	return true;
}

void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
{
	if(0 != *tempfile) {
		(void)fclose(*tempfile);
		*tempfile = 0;
	}

	if(0 != *tempfilename) {
		(void)unlink(*tempfilename);
		free(*tempfilename);
		*tempfilename = 0;
	}
}

bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
{
	FLAC__ASSERT(0 != filename);
	FLAC__ASSERT(0 != tempfile);
	FLAC__ASSERT(0 != tempfilename);
	FLAC__ASSERT(0 != *tempfilename);

	if(0 != *tempfile) {
		(void)fclose(*tempfile);
		*tempfile = 0;
	}

#if defined _MSC_VER || defined __MINGW32__
	if(unlink(filename) < 0) {
		cleanup_tempfile_(tempfile, tempfilename);
		return false;
	}
#endif

	if(0 != rename(*tempfilename, filename)) {
		cleanup_tempfile_(tempfile, tempfilename);
		return false;
	}

	cleanup_tempfile_(tempfile, tempfilename);

	return true;
}

bool get_file_stats_(const char *filename, struct stat *stats)
{
	FLAC__ASSERT(0 != filename);
	FLAC__ASSERT(0 != stats);
	return (0 == stat(filename, stats));
}

void set_file_stats_(const char *filename, struct stat *stats)
{
	struct utimbuf srctime;

	FLAC__ASSERT(0 != filename);
	FLAC__ASSERT(0 != stats);

	srctime.actime = stats->st_atime;
	srctime.modtime = stats->st_mtime;
	(void)chmod(filename, stats->st_mode);
	(void)utime(filename, &srctime);
#if !defined _MSC_VER && !defined __MINGW32__
	(void)chown(filename, stats->st_uid, (gid_t)(-1));
	(void)chown(filename, (uid_t)(-1), stats->st_gid);
#endif
}

#ifdef FLAC__VALGRIND_TESTING
static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, ::FLAC__IOHandle handle)
{
	FILE *stream = (FILE*)handle;
	size_t ret = fwrite(ptr, size, nmemb, stream);
	if(!ferror(stream))
		fflush(stream);
	return ret;
}
#endif

static int chain_seek_cb_(::FLAC__IOHandle handle, FLAC__int64 offset, int whence)
{
	long o = (long)offset;
	FLAC__ASSERT(offset == o);
	return fseek((FILE*)handle, o, whence);
}

static FLAC__int64 chain_tell_cb_(::FLAC__IOHandle handle)
{
	return ftell((FILE*)handle);
}

static int chain_eof_cb_(::FLAC__IOHandle handle)
{
	return feof((FILE*)handle);
}

static bool write_chain_(FLAC::Metadata::Chain &chain, bool use_padding, bool preserve_file_stats, bool filename_based, const char *filename)
{
	if(filename_based)
		return chain.write(use_padding, preserve_file_stats);
	else {
		::FLAC__IOCallbacks callbacks;

		memset(&callbacks, 0, sizeof(callbacks));
		callbacks.read = (::FLAC__IOCallback_Read)fread;
#ifdef FLAC__VALGRIND_TESTING
		callbacks.write = chain_write_cb_;
#else
		callbacks.write = (::FLAC__IOCallback_Write)fwrite;
#endif
		callbacks.seek = chain_seek_cb_;
		callbacks.eof = chain_eof_cb_;

		if(chain.check_if_tempfile_needed(use_padding)) {
			struct stat stats;
			FILE *file, *tempfile;
			char *tempfilename;
			if(preserve_file_stats) {
				if(!get_file_stats_(filename, &stats))
					return false;
			}
			if(0 == (file = fopen(filename, "rb")))
				return false; /*@@@ chain status still says OK though */
			if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
				fclose(file);
				cleanup_tempfile_(&tempfile, &tempfilename);
				return false; /*@@@ chain status still says OK though */
			}
			if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks, (::FLAC__IOHandle)tempfile, callbacks)) {
				fclose(file);
				fclose(tempfile);
				return false;
			}
			fclose(file);
			fclose(tempfile);
			file = tempfile = 0;
			if(!transport_tempfile_(filename, &tempfile, &tempfilename))
				return false;
			if(preserve_file_stats)
				set_file_stats_(filename, &stats);
		}
		else {
			FILE *file = fopen(filename, "r+b");
			if(0 == file)
				return false; /*@@@ chain status still says OK though */
			if(!chain.write(use_padding, (::FLAC__IOHandle)file, callbacks))
				return false;
			fclose(file);
		}
	}

	return true;
}

static bool read_chain_(FLAC::Metadata::Chain &chain, const char *filename, bool filename_based)
{
	if(filename_based)
		return chain.read(filename);
	else {
		::FLAC__IOCallbacks callbacks;

		memset(&callbacks, 0, sizeof(callbacks));
		callbacks.read = (::FLAC__IOCallback_Read)fread;
		callbacks.seek = chain_seek_cb_;
		callbacks.tell = chain_tell_cb_;

		{
			bool ret;
			FILE *file = fopen(filename, "rb");
			if(0 == file)
				return false; /*@@@ chain status still says OK though */
			ret = chain.read((::FLAC__IOHandle)file, callbacks);
			fclose(file);
			return ret;
		}
	}
}

/* function for comparing our metadata to a FLAC::Metadata::Chain */

static bool compare_chain_(FLAC::Metadata::Chain &chain, unsigned current_position, FLAC::Metadata::Prototype *current_block)
{
	unsigned i;
	FLAC::Metadata::Iterator iterator;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -