此文仅用于学习MediaCodec及相关类很实用。
基于上一个文章 https://blog.csdn.net/h2948203216/article/details/103695128
花了一个半月进行修改,可以说很难找到毛病了,当然也不是自夸,主要是被导师逼着一直改这一个demo,一段时间后,想放弃也不想放弃,就干脆仔仔细细写下去了。
没有再沿用上篇转码的代码了,而是升级了新的方式,将decoder到encoder的这一个过程和encode,mux放在一个线程里,那么思路就变成了,read & write,可谓简洁明了,而且read可以一直下去,write也可以一直下去,不用担心需要裁剪一段就要塞EOF指令阻塞编解码器。
之前的思路比较局限,考虑不周,将PST(播放时间戳)的计算放在了encode那里,结果就导致了,因为线程不同的原因,没办法精准控制,因为timeA/V要每段控制,startTime要每段控制,后者要保证当以视频帧为基准时,音频线程必须慢于视频线程才能保证startTime准确,反之视频比音频慢也是如此。而前者timeA/V控制就需要保证知道每段encode结束后的计算,那么只能通过塞EOF阻塞编解码器来达成目的。所以每段结束都需要重置codec,即类似于initxxxCodec()。
而新的思路就是read一直下去,write一直下去,直到最后一个TailTimer给出,当读完时再给出EOF指令阻塞编解码器。
话不多说,给出代码
public class TransCodeWrapper1 {
private static final String TAG = TransCodeWrapper1.class.getName();
private static final int AV_GAP = 500000; // 500MS
private Thread inputLoop, outputLoop;
private List<TailTimer> fileList;
private AssetFileDescriptor srcFilePath;
private String dstFilePath;
private long startTime = 0;
private long endTime = 0;
private long TIMEUS = 70000L;
private MediaExtractor audioExtractor, videoExtractor;
private int audioTrackIndex = -1;
private int videoTrackIndex = -1;
private int videoIndex = -1;
private int audioIndex = -1;
private MediaCodec audioDecoder, audioEncoder;
private MediaCodec videoDecoder, videoEncoder;
private MediaMuxer mediaMuxer;
private long audioEncoderInputTimestamp = 0, videoEncoderInputTimestamp = 0;
private long audioReadTimestamp, videoReadTimestamp;
private int width,height,bitRate,frameRate;
private int iframeInterval = 1;
private int sampleRate,audioBitRate,channelCount;
private String audioFormatType,videoFormatType;
private boolean pauseTime = false;
private boolean isMuxerStarted = false;
private long gapaA = 0;
private long gapaV = 0;
private long gapbA = 0;
private long gapbV = 0;
public TransCodeWrapper1(String dstFilePath , List<TailTimer> fileList) throws IOException{
this.dstFilePath = dstFilePath;
this.fileList = fileList;
initExtractor();
initAudioCodec();
initVideoCodec();
initMuxer();
inputLoop = new Thread(new Runnable() {
@Override
public void run() {
inputLoopInterface();
while(!pauseTime){
try {
Thread.sleep(0L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
audioExtractor.release();
videoExtractor.release();
Log.v(TAG , "extractor released");
audioDecoder.stop();
audioDecoder.release();
Log.v(TAG,"released audioDecode");
videoDecoder.stop();
videoDecoder.release();
Log.v(TAG,"released videoDecode");
}
});
outputLoop = new Thread(new Runnable() {
@Override
public void run() {
outputLoopInterface();
audioEncoder.stop();
videoEncoder.stop();
audioEncoder.release();
videoEncoder.release();
mediaMuxer.stop();
mediaMuxer.release();
Log.v(TAG,"released mediaMuxer");
}
});
}
public int startTranscode() {
inputLoop.start();
outputLoop.start();
return 0;
}
public int stop() {
return 0;
}
private int initExtractor() throws IOException{
if (videoExtractor == null){
videoExtractor = new MediaExtractor();
}
if (audioExtractor == null){
audioExtractor = new MediaExtractor();
}
videoExtractor.setDataSource(fileList.get(0).getSrcPath());
audioExtractor.setDataSource(fileList.get(0).getSrcPath());
for (int i = 0; i < videoExtra