Android h264視頻與G711轉碼合併MP4文件
首先轉碼音頻
音頻轉碼使用EasyAACEncoder 此是EasyDarwin開源流媒體服務團隊整理、開發的一款音頻轉碼到AAC的工具庫編譯的轉碼庫。
具體庫怎麼編譯請看我的另一篇文章:Android G711(PCMA/PCMU)、G726、PCM音頻轉碼到AAC
具體Android怎麼使用該庫方法
使用方法示例:
/**
* g711a轉碼爲aac
*
* @param cachePath 文件路徑
* @param inFilename 輸入音頻文件名
* @param outAacname 輸出音頻文件名
*/
public void g711toAAC(final String cachePath, final String inFilename, final String outAacname) {
new Thread(new Runnable() {
@Override
public void run() {
JNIAACEncode.init(JNIAACEncode.Law_ALaw);
File audiofile = new File(cachePath, inFilename);
File audiofile2 = new File(cachePath, outAacname);
int encode = JNIAACEncode.encode(audiofile.getAbsolutePath(), audiofile2.getAbsolutePath());
if (encode == 0) {
ToastUtil.showMessage("聲音轉碼成功");
}else{
ToastUtil.showMessage("聲音轉碼失敗");
}
}
}).start();
}
注意此處需要編譯的so庫文件,具體文件可以自行編譯或者請查看我上面的文章裏下載編譯好的庫。
然後新建個Java類例如:
public class JNIAACEncode {
public static final int Law_ULaw = 0;/**< U law */
public static final int Law_ALaw = 1;/**< A law */
public static final int Law_PCM16 = 2;/**< 16 bit uniform PCM values. 原始 pcm 數據 */
public static final int Law_G726 = 3;/**< G726 */
//首先進行實例化audioCodec爲上面聲明的音頻類型
public static native void init(int audioCodec);
//原音頻文件路徑與轉碼後的音頻文件路徑
public static native int encode(String infilename, String outAacname);
static {
System.loadLibrary("AACEncode");
}
}
h264與aac合併MP4
上面方法可以把g711音頻文件轉碼成aac文件,然後那h264文件與aac文件進行合併MP4文件,轉碼方法有很多,網上教程也很多,不過好多都要進行編譯so庫文件,整起來很是費勁而且導致項目很大。
但是java有工具進行轉碼,那就是isoparser,該爲jar文件直接放到lib裏即可使用,簡直方便的不要不要,而且很小!比那編譯的庫小很多的!使用也很簡單哈。
至於isoparser可以自行下載,不想動手的可以點我下載isoparser-1.1.21.jar
然後怎麼使用呢,請看本人的使用方法:
/**
* h264視頻進行轉碼爲MP4
* <p/>
* Creates a new Track object from a raw H264 source (DataSource fc). Whenever the timescale and frametick are set to negative value (e.g. -1) the H264TrackImpl tries to detect the frame rate. Typically values for timescale and frametick are:
* 23.976 FPS: timescale = 24000; frametick = 1001
* 25 FPS: timescale = 25; frametick = 1
* 29.97 FPS: timescale = 30000; frametick = 1001
* 30 FPS: timescale = 30; frametick = 1
* Parameters:
* fc - the source file of the H264 samples
* lang - language of the movie (in doubt: use "eng")
* timescale - number of time units (ticks) in one second
* frametick - number of time units (ticks) that pass while showing exactly one frame
*
* @param path h264文件路徑
* @param audioPath aac聲音文件路徑
* @param videoPath 保存視頻文件路徑
* @param fileName 保存視頻文件名
*/
public void saveVideo(final String path, final String audioPath, final String videoPath, final String fileName) {
new Thread(new Runnable() {
@Override
public void run() {
try {
DataSource video_file = new FileDataSourceImpl(path);
H264TrackImpl h264Track = new H264TrackImpl(video_file, "eng", fps, 1);
Movie movie = new Movie();
movie.addTrack(h264Track);
File audiofile = new File(audioPath);
//如果音頻文件不存在,則不合成音頻,存在則加上音頻
if (audiofile.exists()) {
AACTrackImpl aacTrack = null;
try {
DataSource audio_file = new FileDataSourceImpl(audioPath);
aacTrack = new AACTrackImpl(audio_file);
} catch (IOException e) {
e.printStackTrace();
}
movie.addTrack(aacTrack);
}
File myCaptureFile = new File(videoPath);
if (!myCaptureFile.exists() ) {
myCaptureFile.mkdirs();
}
Container out = new DefaultMp4Builder().build(movie);
final File file = new File(myCaptureFile, fileName);
FileOutputStream fos = new FileOutputStream(file);
out.writeContainer(fos.getChannel());
fos.close();
//LogMsg.i(TAG, "視頻轉碼完成");
runOnUiThread(new Runnable() {
@Override
public void run() {
// 最後通知圖庫更新
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
上面方法的fps要根據你合成的視頻具體來設置。
可以參考一下:
23.976 FPS: timescale = 24000; frametick = 1001
25 FPS: timescale = 25; frametick = 1
29.97 FPS: timescale = 30000; frametick = 1001
30 FPS: timescale = 30; frametick = 1
這樣就可以完成視頻的合成啦,當然別忘了加上需要的權限比如讀寫權限。
是不是很方便啦啦,還有就是如果視頻合成後播放如果沒有到播放進度最後就播放完了,那是給關鍵幀有關係,如果你的視頻最後沒有關鍵幀話可能導致後面一段不能播放。