MediaCodec实现转码(重置codec)

 

此文可用于学习MediaCodec的使用,没有涉及到转码所需的格式修改。

与低配版文件转码 https://blog.csdn.net/h2948203216/article/details/102838871 类似,都是多线程跑的转码。大致流程也没什么修改,代码注释都有写,也就不多说了。

唯一的臭毛病就是都在每一段结束后塞EOF阻塞编解码器,导致需要初始化codec或者重置codec。

替换initXXXCodec的方式,根据MediaCodec的状态转换图,我尝试了flush刷新,无效;尝试了stop,Configure,start,无效。

最终使用了reset,configure,start,成功。

也就是调用如下:

initxxxCodec()

->

xxxcodec.reset();
xxxcodec.configure(,,,);
xxxcodec.start();

如此Codec可以再次使用。

话不多说,上代码



public class TranscodeWrapperDemo3 {
    /private  //
    private List<TailTimer> fileList;
    private MediaExtractor extractor,audioExtractor;

    private MediaCodec decodec,encodec,audioDecodec,audioEncodec;

    private MediaMuxer muxer;
    private String filePath;
    private AssetFileDescriptor srcFilePath = null;
    private AssetFileDescriptor srcFilePath2 = null;
    private int isMuxed = 0;
    private int audioTrackIndex = -1 ;
    private int videoTrackIndex = -1 ;
    private int videoIndex  = -1;
    private int audioIndex = -1;
    private boolean isMuxerStarted = false;
    private double assignSizeRate = 1.0;
    private double durationTotal = 0;
    private long TIME_US = 70000L;
    private long startTime1 = 0;
    private long endTime1 = 0;
    private long startTime2 = 0;
    private long endTime2 = 0;
    private boolean isNeedTailed = false;
    private long timeA = 0;
    private long timeV = 0;
    private long startsTime1 = 0;
//    private long startsTime2 = 0;

    /**
     * @param startTime  视频起始解码时间戳
     * @param endTime    视频终止解码时间戳
     */
    private  void setTailTimeVideo(long startTime,long endTime){
        long s = 0;
        long e = (long)durationTotal;
        startTime *= 1000000;
        endTime *= 1000000;
        this.startTime1 = startTime > s ? startTime  : s;
        this.endTime1 = (endTime < e) && (endTime != 0) ? endTime : e;
        this.isNeedTailed = (startTime > 0) || (endTime < e);
    }

    /**
     *
     * @param startTime   音频起始解码时间戳
     * @param endTime     音频终止解码时间戳
     */
    private  void setTailTimeAudio(long startTime , long endTime){
        long s = 0;
        long e = (long)durationTotal;
        startTime *= 1000000;
        endTime *= 1000000;
        this.startTime2 = startTime > s ? startTime  : s;
        this.endTime2 = (endTime < e) && (endTime != 0) ? endTime : e;
        this.isNeedTailed = (startTime > 0) || (endTime < e);

    }


    TranscodeWrapperDemo3(String filePath , List<TailTimer> fileList){
        this.filePath = filePath;
        this.fileList = fileList;
        initMediaMuxer();
        initVideoExtractor();
        initAudioExtractor();
        initVideoDecodec();
        initVideoEncodec();
        initAudioDecodec();
        initAudioEncodec();
    }

    /**
     *  pauseAudio 控制音频比视频慢,保证音频线程每一段可以取到同一段视频的基准也就是第一帧关键帧
     */
    private boolean pauseAudio = true;
    /**
     * 以下总是先初始化codec再执行操作的原因是因为,后一段使用codec的时候,因为第一段接受了EOS指令导致codec停止工作,所以需要重置
     * 而我这里没有重置,而是新建一个
     * 替代方案:
     *      codec.reset()
     *      codec.configure(format, null, null, 0|MediaCodec.CONFIGURE_FLAG_ENCODE)
     *      codec.start()
     *  以上方案是根据codec状态得到的解决方案,
     *  下面是解释:
     *      codec(uninitiated) -> codec(configured)  -> codec(flushed) -> codec(running) -> codec(EOS) -> codec(released)
     *      这是完整的状态,其中存在的闭环:
     *      codec(running) -> codec(flushed)
     *      codec(EOS) -> codec(flushed)
     *      codec(EOS) -> codec(uninitiated) -> codec(configured) -> codec(flushed) -> codec(running) -> codec(EOS)
     *      有几个状态转换需要调用的方法,就说比较陌生的地方,比如codec(flushed) 调用了dequeueInputBuffer() 就会进入到codec(running)
     *      那running 或 EOS 回到 flushed 就调用flush()即可,不过这里我试过,没用。
     *      所以我就用了第三个闭环,EOS 回到 uninitiated 就调用了reset(),然后就是重置codec正常使用。
     */

    private Thread inputThread = new Thread(new Runnable() {
        @Override
        public void run() {
            if (fileList != null){
                for (int i = 0; i < fileList.size(); i++){
                    initVideoDecodec();
                    TailTimer tailTimer = fileList.get(i);
                    setTailTimeVideo(tailTimer.getStartTime(),tailTimer.getEndTime());
                    inputLoop();
                    Log.d("tag","执行到fileListVideo的"+i);
                }
            }else{
                inputLoop();
            }

            extractor.release();
            decodec.stop();
            decodec.release();
            Log.v("tag","released decode");
        }
    });

    private Thread outputThread = new Thread(new Runnable() {
        @Override
        public void run() {
            if (fileList != null){
         
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值