Mp4提取aac音频

用到的API MediaExtractor MediaMuxer 放在子线程去做,还要注意下手机兼容性(可以测试一下乐视的手机)
流程:从mp4中根据音频轨道的index,然后读取每一帧的数据出来,写入到文件
注意:1.手机兼容性,处理一下异常信息
2.写文件最后一帧也要处理一下

import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Looper;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;

import static android.media.MediaCodec.BUFFER_FLAG_END_OF_STREAM;

/**
 * Created by liugs on 2018/5/25.

 */

public class VideoMediaExtractorAac {

    private static final String AUDIO_MEDIA_TYPE = "audio/";
    private static final int BYTE_BUFFER_LENGTH = 2 * 1024 * 1024;

    private String videoPath;
    private String outputAacPath;
    private boolean isCanceled;
    private boolean isFinished;
    private MediaExtractor mediaExtractor;
    private MediaMuxer mediaMuxer;

    public VideoMediaExtractorAac() {
    }

    /**
     * 从视频文件中取出音频文件
     *
     * @param videoPath     输入视频路径
     * @param outputAacPath 输出音频路径
     * @return
     */
    public boolean getAacFile(String videoPath, String outputAacPath) {
        this.videoPath = videoPath;
        this.outputAacPath = outputAacPath;
        try {
            isFinished = run();
        } catch (IOException e) {
            e.printStackTrace();
            //失败就把任务取消吧!
            cancel();
            return isFinished;
        }
        return isFinished;
    }

    /**
     * 取消任务 并销毁所有资源
     *
     * @param canceled 控制参数 true 停止当前的任务,false 不停止当前的任务
     */
    public void cancel(boolean canceled) {
        isCanceled = canceled;
    }

    public boolean isCanceled() {
        return isCanceled;
    }

    public boolean isFinished() {
        return isFinished;
    }

    private boolean run() throws IOException {

        boolean checkWorkedChildThread = checkCurrentThreadIsChildThread();
        if (checkWorkedChildThread) {
            notifyError("You have to do this task in a subthread,for example user thread or Runnable");
            return false;
        }

        boolean fileExit = checkFileExit(videoPath);
        if (!fileExit) {
            notifyError("File not exist !");
            return false;
        }
        boolean isHaveAudio;
        mediaExtractor = new MediaExtractor();
        mediaExtractor.setDataSource(videoPath);
        if (mediaExtractor == null) {
            notifyError("mediaExtractor is null !");
            return false;
        }
        int audioTrackIndex = getMediaTrackIndex(mediaExtractor, AUDIO_MEDIA_TYPE);
        isHaveAudio = audioTrackIndex < 0;
        if (isHaveAudio) {
            notifyError("not find audio form video !");
            return false;
        }
        mediaExtractor.selectTrack(audioTrackIndex);
        MediaFormat audioFormat = mediaExtractor.getTrackFormat(audioTrackIndex);
        mediaMuxer = new MediaMuxer(outputAacPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        int audioIndex = mediaMuxer.addTrack(audioFormat);
        mediaMuxer.start();
        ByteBuffer audioBuffer = ByteBuffer.allocate(BYTE_BUFFER_LENGTH);
        boolean isAudioEnd = false;
        notifyPrepared();
        // init MediaExtractor MediaMuxer
        if (checkIsCanceled()) return false;
        while (true) {
            //working
            if (checkIsCanceled()) return false;
            int sampleSize = mediaExtractor.readSampleData(audioBuffer, 0);
            if (sampleSize <= 0) {
                isAudioEnd = true;
                MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                info.offset = 0;
                info.size = 0;
                info.flags = BUFFER_FLAG_END_OF_STREAM;
                info.presentationTimeUs = 0;
                notifyWorking(info);
                mediaMuxer.writeSampleData(audioIndex, audioBuffer, info);
            } else {
                MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                info.offset = 0;
                info.size = sampleSize;
                info.flags = mediaExtractor.getSampleFlags();
                info.presentationTimeUs = mediaExtractor.getSampleTime();
                notifyWorking(info);
                mediaMuxer.writeSampleData(audioIndex, audioBuffer, info);
            }
            if (isAudioEnd) {
                break;
            }
            mediaExtractor.advance();
        }
        release();
        isFinished = true;
        notifyCompletion();
        //工作结束
        return true;
    }

    private boolean checkCurrentThreadIsChildThread() {
        return Thread.currentThread() != Looper.getMainLooper().getThread();
    }

    private boolean checkIsCanceled() {
        if (isCanceled) {
            cancel();
            notifyError("the work is canceled !");
            return true;
        }
        return false;
    }

    private void cancel() {
        isCanceled = false;
        if (!isFinished) {
            release();
        }
        clearFile();
    }

    private void release() {
        try {
            if (mediaMuxer != null) {
                mediaMuxer.stop();
                mediaMuxer.release();
                mediaMuxer = null;
            }
            if (mediaExtractor != null) {
                mediaExtractor.release();
                mediaExtractor.release();
                mediaExtractor = null;
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    private void clearFile() {
        File file = new File(outputAacPath);
        if (file.exists()) {
            file.deleteOnExit();
        }
    }

    private boolean checkFileExit(String filePath) {
        File file = new File(filePath);
        return file.exists();
    }

    private int getMediaTrackIndex(MediaExtractor videoExtractor, String mediaType) {
        int trackIndex = -1;
        for (int i = 0; i < videoExtractor.getTrackCount(); i++) {
            MediaFormat mediaFormat = videoExtractor.getTrackFormat(i);
            String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
            if (mime.startsWith(mediaType)) {
                trackIndex = i;
                break;
            }
        }
        return trackIndex;
    }

    private OnWorkListener listener;

    public void setListener(OnWorkListener listener) {
        this.listener = listener;
    }

    private void notifyPrepared() {
        if (listener != null) {
            listener.onPrepared();
        }
    }

    private void notifyWorking(MediaCodec.BufferInfo info) {
        if (listener != null) {
            listener.onWorking(info.presentationTimeUs);
        }
    }

    private void notifyCompletion() {
        if (listener != null) {
            listener.onCompletion(videoPath, outputAacPath);
        }
    }

    private void notifyError(String errorStr) {
        if (listener != null) {
            listener.onError(errorStr);
        }
    }

    public interface OnWorkListener {
        void onPrepared();

        void onWorking(long presentationTimeUs);

        void onCompletion(String videoPath, String outPutAudioPath);

        void onError(String errorStr);
    }
}

同样,提取H264需要从视频轨道读取数据!

mediaType:
private static final String AUDIO_MEDIA_TYPE = "video/";

音视频开发问题建议可以发我邮箱 liugstick@163.com

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 来源 微信 Android 视频编码爬过的那些坑 Android的视频相关的开发,大概一直是整个Android生态...
    CHSmile阅读 1,844评论 0 6
  • 你们这些外地人,怎么知道下扬州的奥义。 上回书说到在扬州都要吃些什么以及哪里比较可能吃到好吃的东西,淮扬菜作为中国...
    清热解毒陳槑槑阅读 450评论 0 1
  • 之所以选择这本书,完全是出于学生时代对科幻小说的喜爱,当时爸妈给的零花钱都买了科幻小说杂志,现在那些杂志都...
    王昱阅读 222评论 0 0
  • 昨天妈才跟我讲了对我而言打击够大的事 讲实话我在走回外公家的路上 看到那些不变和巨变的景象从车窗外面迅速后退 也就...
    圣岚阅读 172评论 0 0