视频解码测试程序

1、获取系统支持的编解码器列表

Log.d(TAG, "getVideoCodecList:");
final MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
for (MediaCodecInfo info : list.getCodecInfos()) {
    for (String type : info.getSupportedTypes()) {
        Log.d(TAG, "codec:" + info.getName() + ",MIME=" + type);
    }
}

2、从文件读取视频裸流进行解码

package com.huangchao.codectest;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceView;
import android.widget.Button;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "CodecTest";
    private final static String MIME_TYPE = "video/avc";
    private final static int VIDEO_WIDTH = 1920;
    private final static int VIDEO_HEIGHT = 1080;
    private final static int TIME_INTERNAL = 40;
    private final static int HEAD_OFFSET = 4;
    private final static int readBufferLen = 200000;
    private final static int workBufferLen = readBufferLen * 2;
    Thread readFileThread;
    boolean isInit = false;
    int mCount = 0;
    private File h264File;
    private InputStream is = null;
    private SurfaceView mSurfaceView;
    private MediaCodec mCodec;

    Runnable readRunnable = new Runnable() {
        @Override
        public void run() {
            int workFilledLen = 0;
            byte[] readBuffer = new byte[readBufferLen];
            byte[] workBuffer = new byte[workBufferLen];
            boolean readFlag = true;
            try {
                FileInputStream fs = new FileInputStream(h264File);
                is = new BufferedInputStream(fs);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            while (!Thread.interrupted() && readFlag) {
                try {
                    int length = is.available();
                    if (length > 0) {
                        int count = is.read(readBuffer);
                        if (workFilledLen + count >= workBufferLen) {
                            Log.e(TAG, "invalid data size: " + workFilledLen);
                            workFilledLen = 0;
                        }
                        System.arraycopy(readBuffer, 0, workBuffer,
                                workFilledLen, count);
                        workFilledLen += count;
                        // Find H264 head
                        int nextFrameIndex = findHead(workBuffer, workFilledLen);
                        while (nextFrameIndex > 0) {
                            if (checkHead(workBuffer, 0)) {
                                if (onFrame(workBuffer, 0, nextFrameIndex)) {
                                    //Log.d(TAG, "Loop: workFilledLen: " + workFilledLen + ", nextFrameIndex = " + nextFrameIndex);
                                    byte[] temp = workBuffer;
                                    workBuffer = new byte[workBufferLen];
                                    System.arraycopy(temp, nextFrameIndex, workBuffer,
                                            0, workFilledLen - nextFrameIndex);
                                    workFilledLen -= nextFrameIndex;
                                    nextFrameIndex = findHead(workBuffer, workFilledLen);
                                }
                            } else {
                                Log.e(TAG, "Should never run, skip a frame.");
                                Log.e(TAG, "Error: workFilledLen: " + workFilledLen + ", nextFrameIndex = " + nextFrameIndex);
                                byte[] temp = workBuffer;
                                workBuffer = new byte[workBufferLen];
                                System.arraycopy(temp, nextFrameIndex, workBuffer,
                                        0, workFilledLen - nextFrameIndex);
                                workFilledLen -= nextFrameIndex;
                                nextFrameIndex = findHead(workBuffer, workFilledLen);
                            }
                        }
                    } else {
                        workFilledLen = 0;
                        readFlag = false;
                        // 循环播放
                        //readFileThread = new Thread(readFile);
                        //readFileThread.start();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    };

    static int findHead(byte[] buffer, int len) {
        int i;
        for (i = HEAD_OFFSET; i < len - 3; i++) {
            if (checkHead(buffer, i))
                break;
        }
        if (i == len - 3) {
            if (buffer[i] == 0 && buffer[i + 1] == 0
                    && buffer[i + 2] == 1) {
                return i;
            }
            return 0;
        }
        if (i == HEAD_OFFSET)
            return 0;
        return i;
    }

    static boolean checkHead(byte[] buffer, int offset) {
        // 00 00 00 01
        if (buffer[offset] == 0 && buffer[offset + 1] == 0
                && buffer[offset + 2] == 0 && buffer[3] == 1)
            return true;
        // 00 00 01
        return buffer[offset] == 0 && buffer[offset + 1] == 0
                && buffer[offset + 2] == 1;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String h264Path = getExternalFilesDir(Environment.DIRECTORY_MOVIES) + "/tmp.h264";
        h264File = new File(h264Path);
        Log.d(TAG, "h264Path: " + h264Path);

        mSurfaceView = findViewById(R.id.surfaceView);
        Button mReadButton = findViewById(R.id.btn_readfile);
        mReadButton.setOnClickListener(v -> {
            if (h264File.exists()) {
                if (!isInit) {
                    initDecoder();
                    isInit = true;
                }

                if (readFileThread == null) {
                    readFileThread = new Thread(readRunnable);
                    readFileThread.start();
                }
            } else {
                Toast.makeText(getApplicationContext(),
                        "H264 file not found", Toast.LENGTH_LONG).show();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        readFileThread.interrupt();
    }

    public void initDecoder() {
        try {
            mCodec = MediaCodec.createDecoderByType(MIME_TYPE);
            MediaFormat mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE,
                    VIDEO_WIDTH, VIDEO_HEIGHT);
            mCodec.configure(mediaFormat, mSurfaceView.getHolder().getSurface(),
                    null, 0);
            mCodec.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean onFrame(byte[] buf, int offset, int length) {
        //Log.d(TAG, "onFrame start");
        int inputBufferIndex = mCodec.dequeueInputBuffer(100);
        //Log.d(TAG, "onFrame index:" + inputBufferIndex);
        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = mCodec.getInputBuffer(inputBufferIndex);
            inputBuffer.clear();
            inputBuffer.put(buf, offset, length);
            mCodec.queueInputBuffer(inputBufferIndex, 0, length, mCount
                    * TIME_INTERNAL * 1000, 0);
            mCount++;
        } else {
            return false;
        }

        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 100);
        while (outputBufferIndex >= 0) {
            mCodec.releaseOutputBuffer(outputBufferIndex, true);
            //Log.d(TAG, "releaseOutputBuffer: " + outputBufferIndex);
            outputBufferIndex = mCodec.dequeueOutputBuffer(bufferInfo, 0);
        }
        //Log.d(TAG, "onFrame end");
        return true;
    }
}

LuckJC/CodecTest

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翻滚吧香香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值