简体   繁体   English

我在使用android mediacodec编码和解码h264时出错了颜色

[英]I got wrong color while encoding and decoding h264 by android mediacodec

I'm learning how to use mediacodec recently,it seems to have some problems.I wrote a demo which gets data from camera preview ,encode it into h264 and decode the h264 onto a surfaceview,but it seems the corlor was wrong,just like this: wrong corlor 我最近在学习如何使用mediacodec,它似乎有一些问题。我写了一个演示,从相机预览中获取数据,将其编码为h264并将h264解码到surfaceview上,但似乎corlor错了,就像这: 错误的科洛尔

i've tried to send the h264 i got over rtp and play by ffplay,the corlor was wrong too. 我试图发送h264我已经超过rtp和ffplay玩,corlor也错了。 i'm confuse about that.anybody knows how to fix it?since i'm new here and not good at English,请多指教(Chinese).Here is my code ` package com.example.androidcodec; 我很困惑。有人知道如何解决这个问题吗?因为我是新来的,不擅长英语,请多指教(中文)。这是我的代码`package com.example.androidcodec;

import java.nio.ByteBuffer;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.util.Log;
import android.view.Surface;

public class Encoder {
    private byte[] sps;
    private byte[] pps;
    private MediaCodec mEncoder;
    private int width, height;
    private byte[] yuv420;
    private byte[] mInfo = null;
    private MediaCodec mDecoder;
    private Surface surface;
    private int framerate;
    private int bitrate;

    public Encoder(int width, int height, int framerate, int bitrate,Surface surface) {
        this.surface = surface;
        this.width = width;
        this.height = height;
        this.framerate = framerate;
        this.bitrate = bitrate;
        yuv420 = new byte[width * height * 3 / 2];
        mEncoder = MediaCodec.createEncoderByType("video/avc");
        MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
        mEncoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mEncoder.start();
    }

    public void close() {
        try {
            mEncoder.stop();
            mEncoder.release();
            mEncoder = null;
            mDecoder.stop();
            mDecoder.release();
            mDecoder = null;
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public int offerEncoder(byte[] input, byte[] output) {
        int pos = 0;
        swapYV12toI420(input, yuv420, width, height);
        ByteBuffer[] inputBuffers = mEncoder.getInputBuffers();
        ByteBuffer[] outputBuffers = mEncoder.getOutputBuffers();
        int inputBufferIndex = mEncoder.dequeueInputBuffer(-1);
        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(yuv420);
            mEncoder.queueInputBuffer(inputBufferIndex, 0, yuv420.length, 0, 0);
        }
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mEncoder.dequeueOutputBuffer(bufferInfo, 0);
        while (outputBufferIndex >= 0) {
            ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
            byte[] outData = new byte[bufferInfo.size];
            outputBuffer.get(outData);
            if (mInfo != null) {
                System.arraycopy(outData, 0, output, pos, outData.length);
                pos += outData.length;
            } else {
                ByteBuffer spsPpsBuffer = ByteBuffer.wrap(outData);
                if (spsPpsBuffer.getInt() == 0x00000001) {
                    mInfo = new byte[outData.length];
                    System.arraycopy(outData, 0, mInfo, 0, outData.length);
                    findSpsAndPps(mInfo);
                    initDecoder();
                }else {
                    return -1;
                }
            }
            mEncoder.releaseOutputBuffer(outputBufferIndex, false);  
            outputBufferIndex = mEncoder.dequeueOutputBuffer(bufferInfo, 0);
        }

        return pos;
    }

    private void initDecoder() {
        mDecoder = MediaCodec.createDecoderByType("video/avc");
        MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
        mediaFormat.setByteBuffer("csd-0"  , ByteBuffer.wrap(sps));
        mediaFormat.setByteBuffer("csd-1", ByteBuffer.wrap(pps));
        mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, height*width);  
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
        mDecoder.configure(mediaFormat, surface, null, 0);
        mDecoder.start();

    }

    public void onFrame(byte[] buf, int offset, int length) {

        ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
        int inputBufferIndex = mDecoder.dequeueInputBuffer(-1);
        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(buf, offset, length);
            int capacity = inputBuffer.capacity();
            Log.e("tag", "capacity < length?"+":"+(capacity < length)+"......................");
            mDecoder.queueInputBuffer(inputBufferIndex, 0, length, System.currentTimeMillis(), 0);
        }

        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mDecoder.dequeueOutputBuffer(bufferInfo, 0);
        Log.e("tag", outputBufferIndex+"onFrame.........................................................");
        while (outputBufferIndex >= 0) {
            mDecoder.releaseOutputBuffer(outputBufferIndex, true);
            outputBufferIndex = mDecoder.dequeueOutputBuffer(bufferInfo, 0);
        }
    }


    // yv12 转 yuv420p yvu -> yuv
    private void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width, int height) {
        System.arraycopy(yv12bytes, 0, i420bytes, 0, width * height);
        System.arraycopy(yv12bytes, width * height + width * height / 4, i420bytes, width * height, width * height / 4);
        System.arraycopy(yv12bytes, width * height, i420bytes, width * height + width * height / 4, width * height / 4);
    }

    private void findSpsAndPps(byte[] config) {
        Log.e("tag", printBuffer(config,0,config.length-1));
        int spsEnd = 1;
        for(int i = 4; i < config.length-4; i ++){
            if(config[i]==0X00 && config[i+1]==0X00 &&config[i+2]==0X00 &&config[i+3]==0X01){
                spsEnd = i-1;
                break;
            }
        }
        Log.e("tag", spsEnd-3+"...............................");
        sps = new byte[spsEnd-3];
        pps = new byte[config.length-spsEnd-5];
        System.arraycopy(config,4,sps,0,spsEnd-3);
        System.arraycopy(config,spsEnd+5,pps,0,config.length-spsEnd-5);
    }

    public byte[] getSps() {
        return sps;
    }

    public byte[] getPps() {
        return pps;
    }

    protected static String printBuffer(byte[] buffer, int start,int end) {
        String str = "";
        for (int i=start;i<end;i++) str+=","+Integer.toHexString(buffer[i]&0xFF);
        return str+"\r\n";
    }
}

` `

我自己解决了这个问题,我在details.parameters.setPreviewFormat中犯了一个错误,应该在预览开始之前调用而不是参数.setPictureFormat。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM