自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用MediaCodec實(shí)現(xiàn)視頻解碼播放

移動(dòng)開發(fā) Android
MediaCodec解碼的過程包括配置、啟動(dòng)、輸入數(shù)據(jù)、獲取解碼數(shù)據(jù)和渲染等步驟,通過這些步驟可以實(shí)現(xiàn)高效的音視頻解碼。

MediaCodec是Android平臺(tái)上的一個(gè)多媒體編解碼器,用于對(duì)音頻和視頻數(shù)據(jù)進(jìn)行編解碼。它可以實(shí)現(xiàn)高效的音視頻編解碼,并且可以與硬件加速器結(jié)合使用,提高編解碼性能。MediaCodec可以用于錄制和播放音視頻,以及進(jìn)行實(shí)時(shí)的音視頻通信等場(chǎng)景。

MediaCodec常用的方法:

  1. createDecoderByType(String mimeType):根據(jù)指定的MIME類型創(chuàng)建解碼器。
  2. createEncoderByType(String mimeType):根據(jù)指定的MIME類型創(chuàng)建編碼器。
  3. configure(MediaFormat format, Surface surface, MediaCrypto crypto, int flags):配置解碼器或編碼器的參數(shù),包括媒體格式、渲染表面、加密等。
  4. start():?jiǎn)?dòng)解碼器或編碼器。
  5. flush():清空解碼器或編碼器的輸入和輸出緩沖區(qū)。
  6. release():釋放解碼器或編碼器的資源。

MediaCodec解碼過程:

  1. 創(chuàng)建MediaCodec對(duì)象:首先需要?jiǎng)?chuàng)建一個(gè)MediaCodec對(duì)象,并指定要進(jìn)行的編解碼操作(編碼或解碼)以及要使用的編解碼器類型。
  2. 配置MediaFormat:接下來需要配置MediaFormat,即指定要解碼的媒體數(shù)據(jù)的格式,包括媒體類型(音頻或視頻)、采樣率、比特率等參數(shù)。
  3. 配置Surface(可選):如果是視頻解碼,可以通過設(shè)置Surface來將解碼后的視頻數(shù)據(jù)直接渲染到Surface上,以實(shí)現(xiàn)視頻播放。
  4. 啟動(dòng)MediaCodec:配置完成后,可以調(diào)用start()方法啟動(dòng)MediaCodec。
  5. 輸入數(shù)據(jù):接下來需要將要解碼的媒體數(shù)據(jù)傳遞給MediaCodec進(jìn)行解碼??梢酝ㄟ^調(diào)用queueInputBuffer()方法將媒體數(shù)據(jù)傳遞給MediaCodec。
  6. 獲取解碼數(shù)據(jù):MediaCodec會(huì)將解碼后的數(shù)據(jù)輸出到指定的Surface或ByteBuffer中,可以通過調(diào)用dequeueOutputBuffer()方法獲取解碼后的數(shù)據(jù)。
  7. 渲染(可選):如果是視頻解碼并且使用了Surface,解碼后的視頻數(shù)據(jù)會(huì)直接渲染到Surface上,如果是音頻解碼或者視頻解碼但不使用Surface,需要將解碼后的數(shù)據(jù)進(jìn)行渲染或播放。
  8. 釋放資源:解碼完成后,需要釋放MediaCodec對(duì)象及相關(guān)資源。

MediaCodec解碼的過程包括配置、啟動(dòng)、輸入數(shù)據(jù)、獲取解碼數(shù)據(jù)和渲染等步驟,通過這些步驟可以實(shí)現(xiàn)高效的音視頻解碼。

播放視頻

使用MediaCodec解碼本地h264文件并播放視頻。

  1. 創(chuàng)建一個(gè)MediaExtractor來讀取h264文件的數(shù)據(jù)流。
  2. 通過MediaFormat獲取視頻文件的格式信息,包括視頻的寬、高、幀率等參數(shù)。
  3. 創(chuàng)建一個(gè)MediaCodec來進(jìn)行視頻解碼。
  4. 將解碼后的視頻幀渲染到Surface上進(jìn)行播放。
// 創(chuàng)建MediaExtractor并指定要解碼的文件路徑
MediaExtractor extractor = new MediaExtractor();
extractor.setDataSource(path);

// 獲取視頻文件的格式信息
MediaFormat format = null;
for (int i = 0; i < extractor.getTrackCount(); i++) {
    format = extractor.getTrackFormat(i);
    String mime = format.getString(MediaFormat.KEY_MIME);
    if (mime.startsWith("video/")) {
        extractor.selectTrack(i);
        break;
    }
}

// 創(chuàng)建MediaCodec并配置解碼器
MediaCodec codec = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME));
codec.configure(format, surface, null, 0);
codec.start();

// 讀取并解碼視頻幀
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
boolean isEOS = false;
while (!isEOS) {
    int inputBufferIndex = codec.dequeueInputBuffer(10000);
    if (inputBufferIndex >= 0) {
        ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
        int sampleSize = extractor.readSampleData(inputBuffer, 0);
        if (sampleSize < 0) {
            codec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            isEOS = true;
        } else {
            codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0);
            extractor.advance();
        }
    }

    int outputBufferIndex = codec.dequeueOutputBuffer(info, 10000);
    if (outputBufferIndex >= 0) {
        codec.releaseOutputBuffer(outputBufferIndex, true);
    }
}

// 釋放資源
codec.stop();
codec.release();
extractor.release();

具體實(shí)現(xiàn):

// 解碼工具類

public class H264Player implements Runnable {

    // 本地 h264 文件路徑
    private String path;
    private Surface surface;
    private MediaCodec mediaCodec;
    private Context context;

    public H264Player(Context context, String path, Surface surface) {

        this.context = context;
        this.path = path;
        this.surface = surface;
        try {
            this.mediaCodec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
            // 視頻寬高暫時(shí)寫死
            MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 368, 384);
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
            mediaCodec.configure(mediaFormat, surface, null, 0);
        } catch (IOException e) {
            // 解碼芯片不支持,走軟解
            e.printStackTrace();
        }
    }


    public void play() {
        mediaCodec.start();
        new Thread(this::run).start();
    }

    @Override
    public void run() {
        // 解碼 h264
        decodeH264();
    }

    private void decodeH264() {
        byte[] bytes = null;
        try {
            bytes = getBytes(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 獲取隊(duì)列
        ByteBuffer[] byteBuffers = mediaCodec.getInputBuffers();
        int startIndex = 0;
        int nextFrameStart;
        int totalCount = bytes.length;

        while (true) {
            if (startIndex >= totalCount) {
                break;
            }
            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
            nextFrameStart = findFrame(bytes, startIndex+1,totalCount);
            // 往 ByteBuffer 中塞入數(shù)據(jù)
            int index = mediaCodec.dequeueInputBuffer(10 * 1000);
            Log.e("index",index+"");
            // 獲取 dsp 成功
            if (index >= 0) {
                // 拿到可用的 ByteBuffer
                ByteBuffer byteBuffer = byteBuffers[index];
                byteBuffer.clear();
                byteBuffer.put(bytes, startIndex, nextFrameStart - startIndex);
                // 識(shí)別分隔符,找到分隔符對(duì)應(yīng)的索引
                mediaCodec.queueInputBuffer(index, 0, nextFrameStart - startIndex, 0, 0);
                startIndex = nextFrameStart;

            }else {
                continue;
            }


            // 從 ByteBuffer 中獲取解碼好的數(shù)據(jù)
            int outIndex = mediaCodec.dequeueOutputBuffer(info,10 * 1000);
            if (outIndex > 0){
                try {
                    Thread.sleep(33);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mediaCodec.releaseOutputBuffer(outIndex, true);
            }

        }
    }

    private int findFrame(byte[] bytes, int startIndex, int totalSize) {
        for (int i = startIndex; i < totalSize - 4; i++) {
            if (bytes[i] == 0x00 && bytes[i + 1] == 0x00 && bytes[i + 2] == 0x00 && bytes[i + 3] == 0x01) {
                return i;
            }

        }
        return -1;
    }


    /**
     * 一次性讀取文件
     *
     * @param path
     * @return
     * @throws IOException
     */
    public byte[] getBytes(String path) throws IOException {
        InputStream is = new DataInputStream(new FileInputStream(new File(path)));
        int len;
        int size = 1024;
        byte[] buf;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        buf = new byte[size];
        while ((len = is.read(buf, 0, size)) != -1)
            bos.write(buf, 0, len);
        buf = bos.toByteArray();
        return buf;
    }
    
    public void destroy(){
        if (mediaCodec != null) {
            mediaCodec.stop();
            mediaCodec.release();
        }
    }
}

播放視頻:

public class MainActivity extends AppCompatActivity {

    private H264Player h264Player;

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

    private void initSurface() {
        SurfaceView surfaceView = findViewById(R.id.surface);
        SurfaceHolder surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) {
                h264Player = new H264Player(MainActivity.this, new File(Environment.getExternalStorageDirectory(), "test.h264").getAbsolutePath(), surfaceHolder.getSurface());
                h264Player.play();
            }

            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            }
        });
    }

    private boolean checkPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE
            }, 1);
        }
        return false;
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 停止解碼器
        h264Player.destroy();
    }
}

上述代碼使用MediaCodec來解碼視頻流,并將解碼后的視頻渲染到SurfaceView上,在Activity銷毀時(shí)釋放MediaCodec資源。

責(zé)任編輯:武曉燕 來源: 沐雨花飛蝶
相關(guān)推薦

2024-02-28 08:22:07

2013-07-01 10:53:05

2022-08-26 12:13:08

APIjavascript視頻

2022-03-06 20:02:21

監(jiān)聽視頻播放

2011-07-20 16:21:20

iPhone 視頻 播放器

2011-08-17 14:57:31

iPhone應(yīng)用視頻播放

2022-03-24 15:00:09

Harmony編解碼鴻蒙

2021-08-30 07:49:32

Javascript西瓜視頻

2021-03-17 15:49:03

鴻蒙HarmonyOS應(yīng)用

2023-08-26 19:07:40

VLC旋轉(zhuǎn)視頻

2021-10-29 07:49:23

Python彈幕播放

2011-08-10 15:58:58

iPhone視頻

2014-10-20 09:55:02

2022-08-16 17:37:06

視頻播放器鴻蒙

2022-04-26 14:33:21

鴻蒙操作系統(tǒng)

2021-07-13 09:27:20

AI 解碼視頻

2022-05-12 10:26:57

解碼器Linux

2022-04-15 11:30:59

代碼,Python保存視頻

2023-07-26 17:16:43

微軟Windows

2009-12-15 15:00:00

Fedora Linu
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)