Distribution_Service/CC_SDK/Include/Multimedia/CCMiniMP3.cpp

156 lines
5.5 KiB
C++
Raw Normal View History

2025-11-11 17:46:19 +08:00
#include "CCMiniMP3.h"
#include <cstdio>
#define MINIMP3_IMPLEMENTATION
#include "minimp3.h"
namespace CTL {
MiniMP3::MiniMP3(const char *filename) {
Init(filename);
}
MiniMP3::~MiniMP3() {
if (mp3d) {
delete static_cast<mp3dec_t*>(mp3d);
mp3d = nullptr;
}
}
void MiniMP3::Init(const char *filename) {
// 重置所有成员变量
file_size = -1;
frame_byte_size = -1;
frame_count = -1;
samples_per_frame = -1;
channels = -1;
sampling_rate = -1;
frame_duration = -1;
total_duration = -1;
bit_rate = -1;
is_vbr = false;
has_cover = false;
// 打开文件
FILE* file = fopen(filename, "rb");
if (!file) return;
// 获取文件大小
fseek(file, 0, SEEK_END);
file_size = ftell(file);
fseek(file, 0, SEEK_SET);
// 读取整个文件
mp3Data.resize(file_size);
fread(mp3Data.data(), 1, file_size, file);
fclose(file);
// 初始化minimp3解码器
if (!mp3d) mp3d = new mp3dec_t();
mp3dec_init(static_cast<mp3dec_t*>(mp3d));
// 解析第一帧获取基本信息
mp3dec_frame_info_t info = {};
const int samples = mp3dec_decode_frame(static_cast<mp3dec_t*>(mp3d),
mp3Data.data(), file_size, nullptr, &info);
if (samples > 0) {
this->offsetof_t = info.frame_offset;
frame_byte_size = info.frame_bytes - info.frame_offset; // 每帧字节大小
samples_per_frame = samples; // 每帧样本数
channels = info.channels; // 声道数
sampling_rate = info.hz; // 采样率Hz
frame_duration = static_cast<double>(samples_per_frame) / sampling_rate; // 帧时长(秒)
bit_rate = info.bitrate_kbps; // 比特率bps
is_vbr = info.bitrate_kbps == 0; // 是否为VBR
}
// 计算总帧数和总时长
if (sampling_rate > 0 && samples_per_frame > 0) {
// 遍历所有帧计算总帧数
size_t offset = 0;
frame_count = 0;
int total_samples = 0;
while (offset < mp3Data.size()) {
mp3dec_frame_info_t frame_info = {};
int frame_samples = mp3dec_decode_frame(
static_cast<mp3dec_t*>(mp3d),
mp3Data.data() + offset,
mp3Data.size() - offset,
nullptr,
&frame_info
);
if (frame_samples <= 0 || frame_info.frame_bytes <= 0) break;
++frame_count;
total_samples += frame_samples;
offset += frame_info.frame_bytes;
}
// 计算总时长(毫秒)
total_duration = static_cast<long long>(
(static_cast<double>(total_samples) / sampling_rate) * 1000
) / 1000;
}
}
MiniMP3Frames MiniMP3::GetFrames(bool DecodingPCM) {
MiniMP3Frames result;
if (mp3Data.empty()) return result;
const auto decoder = static_cast<mp3dec_t*>(mp3d);
size_t offset = 0;
while (offset < mp3Data.size()) {
mp3dec_frame_info_t info = {};
mp3d_sample_t pcm[MINIMP3_MAX_SAMPLES_PER_FRAME] = {0};
// 查找下一帧
int samples = mp3dec_decode_frame(decoder,
mp3Data.data() + offset,
mp3Data.size() - offset,
pcm, &info);
if (samples <= 0 || info.frame_bytes <= 0) break;
// 将帧数据添加到结果中
std::vector<uint8_t> frameData(
mp3Data.begin() + offset,
mp3Data.begin() + offset + info.frame_bytes
);
Frame frame;
frame.frame = std::move(frameData);
frame.length = frame.frame.size();
result.frames.push_back(frame);
if (DecodingPCM && (samples * info.channels == MINIMP3_MAX_SAMPLES_PER_FRAME)) {
PCM_Int16 PCM;
PCM.frame.assign(pcm, pcm + samples * info.channels);
PCM.length = PCM.frame.size();
result.PCM.push_back(PCM);
}
offset += info.frame_bytes;
}
result.length = result.frames.size();
return result;
}
PCM_Int16 MiniMP3::GetPCM(const size_t frame_index) const {
PCM_Int16 result;
if (frame_index < mp3Data.size()) {
const auto decoder = static_cast<mp3dec_t*>(mp3d);
const size_t offset = this->offsetof_t;
const size_t Index = offset + frame_index * frame_byte_size;
mp3dec_frame_info_t info = {};
mp3d_sample_t pcm[MINIMP3_MAX_SAMPLES_PER_FRAME] = {0};
int samples = mp3dec_decode_frame(decoder,
mp3Data.data() + Index,
mp3Data.size() - Index,
pcm, &info);
if (samples <= 0 || info.frame_bytes <= 0) return {};
result.frame.assign(pcm, pcm + samples * info.channels);
result.length = result.frame.size();
result.frames = (result.length / info.channels);
}
return std::move(result);
}
}