ncm: FLAC 解码落地(dr_flac 0.13.4 单头入库) + 缓存键=歌曲ID+音质档位
- 解码分发 decoder.c:magic(fLaC→dr_flac / 其它→minimp3);flac ≤16bit→S16、 >16bit→S32 满幅送 audiod(AUDIO_FMT_S32),rate/ch/bits 按实际流,零 SRC 零裁剪 - song_url_auto 接受 flac(type 权威/url 扩展名兜底),降级语义不变;flac 下载限幅 1GB - 缓存键 song_<id>_<level>.<ext>:同歌同档命中不重下,换档新条目旧档留 LRU; ext 前导点正名(修双点名),lookup 回退历史双点名+旧无档键温和兼容 - audio_out S32 通路(AUDIOD/ALSA/WAV)+ 流死重开按 bits 还原格式 - 验证(0 真实请求):44.1k/16 与 96k/24 自制样本宿主+qemu 帧数/时长精确、 逐样本零误差;mp3 回归逐帧一致;player_flow_sim P1-P6(新 P6 档位键/flac ext)、 cache_evict/cover/pagination/window/audiod_chain sim 全 PASS;mipsel 0 warning - REPORT §19 / VENDOR_NOTES dr_flac 条目;未部署真机(留主会话)
This commit is contained in:
1 parent
80bc191593
commit
70aec677ce
23 files changed
+13377
-110
No files matched your search
@@ -1,13 +1,26 @@
|
||||
/* test/test_decode.c — 播放解码链路验证(宿主):minimp3 解码 mp3 → audio_out(FILE sink) 写 WAV。
|
||||
* 不依赖网络/登录(输入本地 mp3)。验证:解码无错、WAV 非空、时长合理、RT 因子。
|
||||
* 运行:NCM_AUDIO_SINK=file NCM_AUDIO_OUT=/tmp/ncm_decode.wav ./test_decode <path.mp3>
|
||||
/* test/test_decode.c — 播放解码链路验证(宿主/mipsel+qemu):decoder(magic 分发
|
||||
* dr_flac/minimp3,§19)→ audio_out(FILE sink) 写 WAV。不依赖网络/登录(输入本地文件)。
|
||||
* 验证:格式探测正确、rate/ch/bits 按实际流、解码无错、WAV 非空、帧数/时长对、RT 因子。
|
||||
*
|
||||
* 运行:NCM_AUDIO_SINK=file NCM_AUDIO_OUT=/tmp/ncm_decode.wav \
|
||||
* ./test_decode <path> [expect_frames] [expect_rate] [expect_bits]
|
||||
* expect_* 给定时校验(不一致 exit 1);不给则只要求 frames>0。
|
||||
*
|
||||
* 编译(宿主,ncm_app 目录下):
|
||||
* gcc -O2 -Wall -Wextra -DJSMN_HEADER -I. -Icore -I../sdk -I../meow_launcherd \
|
||||
* -Ivendor/minimp3 -Ivendor/dr_flac \
|
||||
* app/test/test_decode.c app/play/decoder.c app/play/audio_out.c \
|
||||
* ../sdk/meow_ui_audio.c ../sdk/meow_ui_log.c -o /tmp/td.o-chain # 见下两行豁免 TU
|
||||
* gcc -O2 -Ivendor/minimp3 -c app/play/minimp3_impl.c -o /tmp/td_mm.o # vendor 豁免
|
||||
* gcc -O2 -Ivendor/dr_flac -c app/play/dr_flac_impl.c -o /tmp/td_df.o # vendor 豁免
|
||||
* (首行改为 -c 逐个或把两个豁免 .o 一并链接:gcc ... -o out/test_decode /tmp/td_mm.o /tmp/td_df.o -lpthread -lm)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "../ncm_app_internal.h" /* 引 audio_out / minimp3 声明 */
|
||||
#include "minimp3_ex.h"
|
||||
#include "../ncm_app_internal.h" /* audio_out 声明 + 全局态 */
|
||||
#include "../play/decoder.h"
|
||||
|
||||
ncm_app_state_t g_st;
|
||||
ncm_play_run_t g_play = { .mu = PTHREAD_MUTEX_INITIALIZER };
|
||||
@@ -15,6 +28,14 @@ volatile int g_app_quit = 0;
|
||||
volatile int g_net_ready = 0;
|
||||
int g_host_mock = 1;
|
||||
|
||||
/* SDK meow_ui_log.c 需要(本测试不链 meow_ui_sys.c,同 audiod_chain_sim 口径打桩) */
|
||||
uint64_t meow_ui_time_ms(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
static double now_s(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
@@ -25,43 +46,45 @@ static double now_s(void)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *path = (argc > 1) ? argv[1] : "vendor/minimp3/vectors/performance/MIPSTest.mp3";
|
||||
mp3dec_ex_t dec;
|
||||
memset(&dec, 0, sizeof dec);
|
||||
if (mp3dec_ex_open(&dec, path, MP3D_SEEK_TO_BYTE) != 0) { fprintf(stderr, "open failed\n"); return 1; }
|
||||
int64_t exp_frames = (argc > 2) ? atoll(argv[2]) : -1;
|
||||
int exp_rate = (argc > 3) ? atoi(argv[3]) : -1;
|
||||
int exp_bits = (argc > 4) ? atoi(argv[4]) : -1;
|
||||
|
||||
static mp3d_sample_t pcm[8192 * 2];
|
||||
/* 读首帧确定采样率/声道(read 会填 dec.info)*/
|
||||
size_t got = mp3dec_ex_read(&dec, pcm, 8192 * 2);
|
||||
int sr = dec.info.hz;
|
||||
int ch = dec.info.channels;
|
||||
if (sr <= 0 || ch <= 0) { fprintf(stderr, "bad stream\n"); return 1; }
|
||||
printf("mp3: %s %dHz x%d detected_samples=%lld bitrate=%dkbps\n",
|
||||
path, sr, ch, (long long)dec.samples, dec.info.bitrate_kbps);
|
||||
if (audio_out_open(sr, ch, 16) != 0) { fprintf(stderr, "audio_out open failed\n"); return 1; }
|
||||
ncm_decoder_t *dec = NULL;
|
||||
int rate = 0, ch = 0, bits = 0;
|
||||
int64_t total_frames = 0;
|
||||
if (ncm_dec_open(&dec, path, &rate, &ch, &bits, &total_frames) != 0) {
|
||||
fprintf(stderr, "open failed\n"); return 1;
|
||||
}
|
||||
printf("%s: %s %dHz x%d %dbit total_frames=%lld\n",
|
||||
path, ncm_dec_format(dec), rate, ch, bits, (long long)total_frames);
|
||||
if (exp_rate > 0 && rate != exp_rate) { fprintf(stderr, "rate mismatch %d != %d\n", rate, exp_rate); return 1; }
|
||||
if (exp_bits > 0 && bits != exp_bits) { fprintf(stderr, "bits mismatch %d != %d\n", bits, exp_bits); return 1; }
|
||||
|
||||
if (audio_out_open(rate, ch, bits) != 0) { fprintf(stderr, "audio_out open failed\n"); return 1; }
|
||||
|
||||
static int32_t pcm[4096 * 2];
|
||||
long long frames = 0;
|
||||
double t0 = now_s();
|
||||
if (got > 0) {
|
||||
int fr = (int)(got / (size_t)ch);
|
||||
if (audio_out_write(pcm, fr) != fr) { fprintf(stderr, "write failed\n"); return 1; }
|
||||
frames += fr;
|
||||
}
|
||||
for (;;) {
|
||||
if (g_app_quit) break;
|
||||
got = mp3dec_ex_read(&dec, pcm, 8192 * 2);
|
||||
int64_t got = ncm_dec_read(dec, pcm, 4096);
|
||||
if (got == 0) break;
|
||||
int fr = (int)(got / (size_t)ch);
|
||||
if (audio_out_write(pcm, fr) != fr) { fprintf(stderr, "write failed\n"); break; }
|
||||
frames += fr;
|
||||
if (audio_out_write(pcm, (int)got) != (int)got) { fprintf(stderr, "write failed\n"); break; }
|
||||
frames += got;
|
||||
}
|
||||
double dt = now_s() - t0;
|
||||
audio_out_close();
|
||||
mp3dec_ex_close(&dec);
|
||||
ncm_dec_close(dec);
|
||||
|
||||
double secs = (double)frames / (double)sr;
|
||||
double secs = rate > 0 ? (double)frames / (double)rate : 0;
|
||||
double rt = (dt > 0) ? secs / dt : 0;
|
||||
printf("decoded %lld frames = %.2f s audio (%d Hz) in %.3f s => %.1fx RT\n",
|
||||
frames, secs, sr, dt, rt);
|
||||
printf("decoded %lld frames = %.3f s audio (%d Hz) in %.3f s => %.1fx RT\n",
|
||||
frames, secs, rate, dt, rt);
|
||||
if (exp_frames >= 0 && frames != exp_frames) {
|
||||
fprintf(stderr, "frames mismatch %lld != %lld\n", frames, (long long)exp_frames);
|
||||
return 1;
|
||||
}
|
||||
printf("OK: %s\n", (frames > 0) ? "decode chain works" : "EMPTY");
|
||||
return (frames > 0) ? 0 : 1;
|
||||
}
|
||||
Reference in new issue
Block a user