Skip to content

Commit 5bdd81a

Browse files
committed
feat: 添加 AAC/M4A/MP4 格式支持
- 新增 AacCodec.java,使用 Android MediaCodec 实现 AAC 编解码 - 支持 MP4/M4A/AAC 解码到 PCM - 支持 PCM 编码到 AAC (ADTS) 和 M4A - 修改 silk_codec.cpp 区分 M4A 和 MP4 文件类型 - C++ 层自动检测并调用 Java AacCodec 处理 AAC/M4A 格式
1 parent 50de94b commit 5bdd81a

7 files changed

Lines changed: 1005 additions & 186 deletions

File tree

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[![Download](https://img.shields.io/badge/Download-JitPack-blueviolet.svg)](https://jitpack.io)
88
[![JitPack](https://jitpack.io/v/YunJavaPro/Silk-Codec-Android.svg)](https://jitpack.io/#YunJavaPro/Silk-Codec-Android)
99

10-
> 轻量级 Android 音频编解码库,基于 Silk SDK / dr_libs / stb_vorbis / lame 实现底层解码,JNI 封装,最高支持 48000Hz 采样率。
10+
> 轻量级 Android 音频编解码库,基于 Silk SDK / dr_libs / stb_vorbis / lame / android_media 实现底层解码,JNI 封装,最高支持 48000Hz 采样率。
1111
1212
---
1313

@@ -27,7 +27,7 @@
2727

2828
| 输入 | 输出 |
2929
|------|------|
30-
| mp3 / wav / flac / ogg / silk / amr / pcm | silk / mp3 / pcm |
30+
| mp3 / wav / flac / ogg / silk / amr / pcm | silk / mp3 / pcm | m4a | mp4
3131

3232
**采样率:** 8000 / 12000 / 16000 / 24000 / 32000 / 44100 / 48000 Hz
3333

@@ -49,7 +49,7 @@ codec.autoToPcm("/sdcard/input.wav", "/sdcard/output.pcm");
4949

5050
// 获取文件类型
5151
int type = codec.getFileType("/sdcard/somefile");
52-
// 返回:0=未知 1=Silk 2=MP3 3=WAV 4=FLAC 5=OGG 6=PCM 7=M4A 8=AAC
52+
// 返回:0=未知 1=Silk 2=MP3 3=WAV 4=FLAC 5=OGG 6=PCM 7=M4A 8=MP4
5353

5454
// 获取音频时长(毫秒)
5555
long duration = codec.getDuration("/sdcard/somefile");
@@ -85,6 +85,20 @@ long duration = codec.getDuration("/sdcard/somefile");
8585
| -701 | PCM 参数错误 |
8686
| -702 | PCM 文件错误 |
8787
| -703 | PCM 参数错误 |
88+
| -801 | AAC/M4A 解码错误 (文件不存在) |
89+
| -802 | AAC/M4A 解码错误 (未找到音频轨道) |
90+
| -803 | AAC/M4A 解码错误 (格式不支持) |
91+
| -901 | AAC 编码错误 (PCM 文件不存在) |
92+
| -902 | AAC 编码错误 (编码异常) |
93+
| -911 | M4A 编码错误 (PCM 文件不存在) |
94+
| -912 | M4A 编码错误 (Muxer 失败) |
95+
| -1001 ~ -1009 | Silk 转 AAC/M4A 错误 |
96+
| -1011 ~ -1012 | MP3 转 AAC/M4A 错误 |
97+
| -1021 ~ -1022 | WAV 转 AAC/M4A 错误 |
98+
| -1031 ~ -1039 | M4A/AAC 转 Silk 错误 |
99+
| -1051 ~ -1059 | M4A/AAC 转 AAC 错误 |
100+
| -1061 ~ -1069 | M4A/AAC 转 M4A 错误 |
101+
| -2000 | M4A/AAC 转 Silk 错误 (解码失败) |
88102

89103
---
90104

app/src/main/java/me/yun/silk/utils/Conversion.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package me.yun.silk.utils;
22

33
import me.yun.silk.SilkCodec;
4+
import me.yun.silk.AacCodec;
45

56
public class Conversion {
67

78
public interface ConversionCallback {
89
void onMessage(String msg);
10+
default void onProgress(int progress) {}
911
}
1012

1113
public static void startTransform(SilkCodec codec, int type, String inputPath, String outputPath, int sampleRate, ConversionCallback callback) {
@@ -20,6 +22,9 @@ public static void startTransform(SilkCodec codec, int type, String inputPath, S
2022
case 1: result = codec.mp3ToSilk(inputPath, outputPath, sampleRate); break;
2123
case 5: result = codec.autoToSilk(inputPath, outputPath, sampleRate); break;
2224
case 6: result = codec.autoToPcm(inputPath, outputPath); break;
25+
case 7: result = AacCodec.autoToAac(inputPath, outputPath, codec, sampleRate); break;
26+
case 8: result = AacCodec.autoToM4a(inputPath, outputPath, codec, sampleRate); break;
27+
case 9: result = AacCodec.m4aToSilk(inputPath, outputPath, codec, sampleRate); break;
2328
}
2429

2530
if (result == 0) {
@@ -33,6 +38,46 @@ public static void startTransform(SilkCodec codec, int type, String inputPath, S
3338
}).start();
3439
}
3540

41+
public static int silkToAac(SilkCodec codec, String silkPath, String aacPath, int hz) {
42+
return AacCodec.silkToAac(silkPath, aacPath, codec, hz);
43+
}
44+
45+
public static int silkToM4a(SilkCodec codec, String silkPath, String m4aPath, int hz) {
46+
return AacCodec.silkToM4a(silkPath, m4aPath, codec, hz);
47+
}
48+
49+
public static int mp3ToAac(String mp3Path, String aacPath, int sampleRate) {
50+
return AacCodec.mp3ToAac(mp3Path, aacPath, sampleRate);
51+
}
52+
53+
public static int mp3ToM4a(String mp3Path, String m4aPath, int sampleRate) {
54+
return AacCodec.mp3ToM4a(mp3Path, m4aPath, sampleRate);
55+
}
56+
57+
public static int wavToAac(String wavPath, String aacPath, int sampleRate) {
58+
return AacCodec.wavToAac(wavPath, aacPath, sampleRate);
59+
}
60+
61+
public static int wavToM4a(String wavPath, String m4aPath, int sampleRate) {
62+
return AacCodec.wavToM4a(wavPath, m4aPath, sampleRate);
63+
}
64+
65+
public static int m4aToSilk(SilkCodec codec, String m4aPath, String silkPath, int hz) {
66+
return AacCodec.m4aToSilk(m4aPath, silkPath, codec, hz);
67+
}
68+
69+
public static int m4aToPcm(String m4aPath, String pcmPath) {
70+
return AacCodec.m4aToPcm(m4aPath, pcmPath);
71+
}
72+
73+
public static int pcmToAac(String pcmPath, String aacPath, int sampleRate, int channels) {
74+
return AacCodec.pcmToAac(pcmPath, aacPath, sampleRate, channels);
75+
}
76+
77+
public static int pcmToM4a(String pcmPath, String m4aPath, int sampleRate, int channels) {
78+
return AacCodec.pcmToM4a(pcmPath, m4aPath, sampleRate, channels);
79+
}
80+
3681
private static String getFileTypeName(int type) {
3782
switch (type) {
3883
case 1: return "Silk";
@@ -66,7 +111,17 @@ private static String getErrorMsg(int code) {
66111
case -501: case -502: return "错误码:" + code + " → WAV 解码错误";
67112
case -601: case -602: return "错误码:" + code + " → FLAC 解码错误";
68113
case -701: case -702: case -703: return "错误码:" + code + " → PCM 参数错误";
114+
case -801: case -802: return "错误码:" + code + " → AAC/M4A 解码错误 (文件读取失败)";
115+
case -803: return "错误码:-803 → AAC/M4A 解码错误 (格式不支持)";
116+
case -901: case -902: return "错误码:" + code + " → AAC/M4A 编码错误";
117+
case -911: case -912: return "错误码:" + code + " → M4A 编码错误";
118+
case -1001: return "错误码:-1001 → Silk 转 AAC/M4A 错误";
119+
case -1011: case -1012: return "错误码:" + code + " → MP3 转 AAC/M4A 错误";
120+
case -1021: case -1022: return "错误码:" + code + " → WAV 转 AAC/M4A 错误";
121+
case -1031: return "错误码:-1031 → AAC/M4A 转 Silk 错误";
122+
case -1041: return "错误码:-1041 → 中间转换错误";
123+
case -2000: return "错误码:-2000 → M4A/AAC 转 Silk 错误 (解码失败)";
69124
default: return "错误码:" + code + " → 未知错误";
70125
}
71126
}
72-
}
127+
}

app/src/main/java/me/yun/silk/utils/UriUtils.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// src/main/java/me/yun/silk/utils/UriUtils.java
21
package me.yun.silk.utils;
32

43
import android.content.ContentUris;
@@ -11,16 +10,10 @@
1110

1211
public class UriUtils {
1312

14-
/**
15-
* 将系统选择返回的 Uri 解析为真实的本地绝对路径
16-
* 取消了拷贝到缓存目录的做法,直接还原原文件路径
17-
*/
1813
public static String getPathFromUri(final Context context, final Uri uri) {
1914
if (uri == null) return null;
2015

21-
// 1. DocumentProvider (系统文件管理器选择的)
2216
if (DocumentsContract.isDocumentUri(context, uri)) {
23-
// ExternalStorageProvider (外部存储)
2417
if (isExternalStorageDocument(uri)) {
2518
final String docId = DocumentsContract.getDocumentId(uri);
2619
final String[] split = docId.split(":");
@@ -32,7 +25,6 @@ public static String getPathFromUri(final Context context, final Uri uri) {
3225
return "/storage/" + type + "/" + split[1];
3326
}
3427
}
35-
// DownloadsProvider (下载目录)
3628
else if (isDownloadsDocument(uri)) {
3729
final String id = DocumentsContract.getDocumentId(uri);
3830
if (id != null && id.startsWith("raw:")) {
@@ -50,7 +42,6 @@ else if (isDownloadsDocument(uri)) {
5042
} catch (Exception ignore) {}
5143
}
5244
}
53-
// MediaProvider (媒体库)
5445
else if (isMediaDocument(uri)) {
5546
final String docId = DocumentsContract.getDocumentId(uri);
5647
final String[] split = docId.split(":");
@@ -70,21 +61,16 @@ else if (isMediaDocument(uri)) {
7061
return getDataColumn(context, contentUri, selection, selectionArgs);
7162
}
7263
}
73-
// 2. MediaStore (and general)
7464
else if ("content".equalsIgnoreCase(uri.getScheme())) {
7565
return getDataColumn(context, uri, null, null);
7666
}
77-
// 3. File
7867
else if ("file".equalsIgnoreCase(uri.getScheme())) {
7968
return uri.getPath();
8069
}
8170

8271
return null;
8372
}
8473

85-
/**
86-
* 解析选择文件夹返回的 Tree Uri,获取真实的绝对路径
87-
*/
8874
public static String getTreePathFromUri(Context context, Uri treeUri) {
8975
if (treeUri == null) return null;
9076

@@ -114,9 +100,6 @@ public static String getTreePathFromUri(Context context, Uri treeUri) {
114100
return null;
115101
}
116102

117-
/**
118-
* 通过游标获取 _data 字段 (即绝对物理路径)
119-
*/
120103
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
121104
Cursor cursor = null;
122105
final String column = "_data";

silk-codec/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ publishing {
4343
create<MavenPublication>("release") {
4444
groupId = "com.github.YunJavaPro"
4545
artifactId = "silk-codec"
46-
version = "1.0.0"
46+
version = "1.0.1"
4747
afterEvaluate {
4848
from(components["release"])
4949
}

0 commit comments

Comments
 (0)