📄 tak_lib_cpp.cpp
字号:
#include "stdafx.h"
#include "tak_lib_cpp.h"
#ifdef _DEBUG
//#define TRACE_IO_INTERFACE
#endif
class format_tak_version
{
pfc::string_formatter data;
public:
explicit format_tak_version(TtakInt32 p_version)
{
data << pfc::format_int((p_version >> 16) & 0xff)
<< "." << pfc::format_int((p_version >> 8) & 0xff)
<< "." << pfc::format_int(p_version& 0xff);
}
operator char const *() {return data;}
};
namespace tak_lib_cpp
{
inline TtakBool tak_bool_cast(bool p_val) {return p_val ? tak_True : tak_False;}
class exception_io_tak_ssd : public std::exception
{
char m_what[tak_ErrorStringSizeMax];
public:
exception_io_tak_ssd(TtakResult p_result)
{
tak_SSD_GetErrorString(p_result, m_what, sizeof(m_what));
};
virtual const char * what() const
{
return m_what;
};
};
TtakStreamIoInterface tak_stream_interface_impl_file::g_io_interface;
TtakBool tak_stream_interface_impl_file::CanRead(void * p_userdata)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
return tak_bool_cast(_this->m_file.is_valid());
}
TtakBool tak_stream_interface_impl_file::CanWrite(void * p_userdata)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
return tak_bool_cast(_this->m_file.is_valid());
}
TtakBool tak_stream_interface_impl_file::CanSeek(void * p_userdata)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
return tak_bool_cast(_this->m_file->can_seek());
}
TtakBool tak_stream_interface_impl_file::Read(void * p_userdata, void * p_buffer, TtakInt32 p_bytes, TtakInt32 * p_read)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
#ifdef TRACE_IO_INTERFACE
console::formatter trace;
#endif
try
{
#ifdef TRACE_IO_INTERFACE
trace << "Read(this, buffer, " << p_bytes << ")";
#endif
t_size read = _this->m_file->read(p_buffer, p_bytes, abort_callback_impl());
#ifdef TRACE_IO_INTERFACE
trace << " succeeded, read " << read << " bytes";
#endif
if (p_read != 0)
*p_read = read;
return tak_True;
}
catch (const std::exception &exc)
{
#ifdef TRACE_IO_INTERFACE
trace << " failed, exception: " << exc;
#else
exc; // avoid warning
#endif
return tak_False;
}
}
TtakBool tak_stream_interface_impl_file::Write(void * p_userdata, const void * p_buffer, TtakInt32 p_bytes)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
try
{
_this->m_file->write(p_buffer, p_bytes, abort_callback_impl());
return tak_True;
}
catch (std::exception)
{
return tak_False;
}
}
TtakBool tak_stream_interface_impl_file::Flush(void * p_userdata)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
try
{
// Null operation.
return tak_True;
}
catch (std::exception)
{
return tak_False;
}
}
TtakBool tak_stream_interface_impl_file::Truncate(void * p_userdata)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
try
{
_this->m_file->set_eof(abort_callback_impl());
return tak_True;
}
catch (std::exception)
{
return tak_False;
}
}
TtakBool tak_stream_interface_impl_file::Seek(void * p_userdata, TtakInt64 p_position)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
#ifdef TRACE_IO_INTERFACE
console::formatter trace;
#endif
try
{
#ifdef TRACE_IO_INTERFACE
trace << "Seek(this, " << p_position << ")";
#endif
_this->m_file->seek(p_position, abort_callback_impl());
#ifdef TRACE_IO_INTERFACE
trace << " succeeded";
#endif
return tak_True;
}
catch (const std::exception &exc)
{
#ifdef TRACE_IO_INTERFACE
trace << " failed, exception: " << exc;
#else
exc; // avoid warning
#endif
return tak_False;
}
}
TtakBool tak_stream_interface_impl_file::GetLength(void * p_userdata, TtakInt64 * p_length)
{
tak_stream_interface_impl_file * _this = static_cast<tak_stream_interface_impl_file *>(p_userdata);
try
{
*p_length = _this->m_file->get_size(abort_callback_impl());
return tak_True;
}
catch (std::exception)
{
return tak_False;
}
}
TtakStreamIoInterface * tak_stream_interface_impl_file::g_get_io_interface_ptr()
{
static bool g_initialized = false;
if (!g_initialized)
{
g_io_interface.CanRead = &CanRead;
g_io_interface.CanSeek = &CanSeek;
g_io_interface.CanWrite = &CanWrite;
g_io_interface.Flush = &Flush;
g_io_interface.GetLength = &GetLength;
g_io_interface.Read = &Read;
g_io_interface.Seek = &Seek;
g_io_interface.Truncate = &Truncate;
g_io_interface.Write = &Write;
g_initialized = true;
}
return &g_io_interface;
}
tak_stream_interface_impl_file::tak_stream_interface_impl_file(service_ptr_t<file> p_file)
{
m_file = p_file;
}
tak_stream_interface_impl_file::~tak_stream_interface_impl_file()
{
}
#ifdef _DEBUG
tak_seekable_decoder::tak_seekable_decoder(const char * p_filename)
{
m_decoder.create_from_file(p_filename, tak_ssd_opt_BufferInput);
if (m_decoder.is_empty())
throw exception_io("TAK decoder could not be created");
if (!m_decoder.is_decoder_valid())
throw exception_io("TAK decoder is in error state");
TtakResult res = m_decoder.get_stream_info(m_info);
if (res != tak_res_Ok)
throw exception_io_tak_ssd(res);
res = m_decoder.get_stream_encoder_info(m_encoder_info);
m_encoder_info_valid = (res == tak_res_Ok);
}
#endif
tak_seekable_decoder::tak_seekable_decoder(service_ptr_t<file> p_file, TtakInt32 p_cpu_opt_flags)
{
m_file_callback = new tak_stream_interface_impl_file(p_file);
m_decoder.create_from_stream(
tak_stream_interface_impl_file::g_get_io_interface_ptr(),
m_file_callback.get_ptr(),
tak_ssd_opt_BufferInput,
p_cpu_opt_flags);
if (m_decoder.is_empty())
throw exception_io("TAK decoder could not be created");
if (!m_decoder.is_decoder_valid())
throw exception_io("TAK decoder is in error state");
TtakResult res = m_decoder.get_stream_info(m_info);
if (res != tak_res_Ok)
throw exception_io_tak_ssd(res);
res = m_decoder.get_stream_encoder_info(m_encoder_info);
m_encoder_info_valid = (res == tak_res_Ok);
}
tak_seekable_decoder::~tak_seekable_decoder()
{
}
void tak_seekable_decoder::seek(TtakInt64 p_sample)
{
TtakResult res = m_decoder.seek(p_sample);
if (res != tak_res_Ok)
throw exception_io_tak_ssd(res);
}
t_size tak_seekable_decoder::decode(void * p_data, t_size p_samples)
{
TtakInt32 read = 0;
TtakResult res = m_decoder.read_audio(p_data, p_samples, read);
if (res != tak_res_Ok)
throw exception_io_tak_ssd(res);
return read;
}
t_uint32 tak_seekable_decoder::get_channel_count()
{
return m_info.Audio.ChannelNum;
}
t_uint32 tak_seekable_decoder::get_sample_rate()
{
return m_info.Audio.SampleRate;
}
t_uint64 tak_seekable_decoder::get_sample_count()
{
return m_info.Sizes.SampleNum;
}
t_uint32 tak_seekable_decoder::get_bits_per_sample()
{
return m_info.Audio.SampleBits;
}
t_uint32 tak_seekable_decoder::get_frame_size()
{
return m_info.Sizes.FrameSizeInSamples;
}
void tak_seekable_decoder::get_info(file_info & p_info)
{
p_info.info_set_int("bitspersample", m_info.Audio.SampleBits);
p_info.info_set_int("channels", m_info.Audio.ChannelNum);
p_info.info_set_int("samplerate", m_info.Audio.SampleRate);
p_info.set_length(audio_math::samples_to_time(m_info.Sizes.SampleNum, m_info.Audio.SampleRate));
//TtakResult result = tak_res_Ok;
//char codec_name[tak_CodecNameSizeMax];
//result = tak_GetCodecName(m_info.Encoder.Codec, codec_name, sizeof(codec_name));
p_info.info_set("codec", "TAK");
if (m_encoder_info_valid)
{
pfc::string8_fastalloc profile;
if (m_encoder_info.Version <= 0x010001)
{
switch (m_encoder_info.Preset)
{
case 0:
profile = "turbo";
break;
case 1:
profile = "fast";
break;
case 2:
profile = "normal";
break;
case 3:
profile = "high";
break;
case 4:
profile = "extra";
break;
default:
profile << m_info.Encoder.Profile;
break;
}
}
else if (m_encoder_info.Version <= 0x010002)
{
switch (m_encoder_info.Preset)
{
case 0:
profile = "turbo";
break;
case 1:
profile = "fast";
break;
case 2:
profile = "normal";
break;
case 3:
profile = "high";
break;
case 4:
profile = "extra";
break;
case 5:
profile = "insane";
break;
default:
profile << m_info.Encoder.Profile;
break;
}
}
else
{
profile << m_info.Encoder.Profile;
}
switch (m_encoder_info.Evaluation)
{
case tak_PresetEval_Standard:
// no additional text
break;
case tak_PresetEval_Extra:
profile << " extra";
break;
case tak_PresetEval_Max:
profile << " max";
break;
default:
break;
}
p_info.info_set("codec_profile", profile);
p_info.info_set("tool", pfc::string_formatter() << "TAK encoder " << format_tak_version(m_encoder_info.Version));
}
else if (m_info.Encoder.Codec == 0)
{
switch (m_info.Encoder.Profile)
{
case 0:
p_info.info_set("codec_profile", "turbo");
break;
case 1:
p_info.info_set("codec_profile", "fast");
break;
case 2:
p_info.info_set("codec_profile", "normal");
break;
case 3:
p_info.info_set("codec_profile", "high");
break;
case 4:
p_info.info_set("codec_profile", "extra");
break;
default:
p_info.info_set_int("codec_profile", m_info.Encoder.Profile);
break;
}
}
#ifdef _DEBUG
p_info.info_set_int("framesize", m_info.Sizes.FrameSizeInSamples);
switch (m_info.Sizes.FrameSize)
{
case tak_str_FrameSizeType_94_ms:
p_info.info_set_int("framesizems", 94);
break;
case tak_str_FrameSizeType_125_ms:
p_info.info_set_int("framesizems", 125);
break;
case tak_str_FrameSizeType_188_ms:
p_info.info_set_int("framesizems", 188);
break;
case tak_str_FrameSizeType_250_ms:
p_info.info_set_int("framesizems", 250);
break;
}
#endif
}
t_int32 tak_seekable_decoder::get_last_frame_bitrate()
{
TtakInt32 result = m_decoder.get_last_frame_bitrate();
return result;
}
} // namespace tak_lib_cpp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -