Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

Кодирование видео в Android

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Помогите разобраться что не так. Во всех примерах что я нагуглил кодеку и миксеру делается просто stop и release.А у меня после этого вместо финализации вайпается все содержимое записанного файла.Думал что формат цвета фрейма не нравится, пробовал и в yuv, и в argb.Но результат все тот же ((( В общем я запутался, подскажите кому не трудно что не так.

public class H264Encoder implements Runnable
{
    private int width=640;
    private int height=480;
    private int frameRate=25;
    private String TAG="H264Encoder";
    private long frameIndex=0;
    private int vTrackIndex;
    /**************************************************************************************/
    private BlockingQueue<Bitmap> dataBuffer;
    private boolean finish=false;
    private MediaCodec.BufferInfo mBufferInfo;
    private MediaCodec mediaCodec,mediaCodecForAudio;
    private MediaFormat mediaFormat;
    private MediaMuxer mediaMuxer;

    public H264Encoder(BlockingQueue<Bitmap> dataBuffer)
    {
        this.dataBuffer = dataBuffer;
    }
    public void Stop()
    {
        this.finish = true;
    }
    private int CalcBitRate(double  coeff/*bit/pixel coefficient*/)
    {
        return (int)(this.height*this.width*this.frameRate*coeff);
    }
    private long computePresentationTime(long frameIndex)
    {
        return 132 + frameIndex * 1000000/this.frameRate;
    }
    private void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
        final int frameSize = width * height;

        int yIndex = 0;
        int uvIndex = frameSize;

        int a, R, G, B, Y, U, V;
        int index = 0;
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {

                a = (argb[index] & 0xff000000) >> 24; // a is not used obviously
                R = (argb[index] & 0xff0000) >> 16;
                G = (argb[index] & 0xff00) >> 8;
                B = (argb[index] & 0xff) >> 0;

                // well known RGB to YUV algorithm
                Y = ( (  66 * R + 129 * G +  25 * B + 128) >> 8) +  16;
                U = ( ( -38 * R -  74 * G + 112 * B + 128) >> 8) + 128;
                V = ( ( 112 * R -  94 * G -  18 * B + 128) >> 8) + 128;

                // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
                //    meaning for every 4 Y pixels there are 1 V and 1 U.  Note the sampling is every other
                //    pixel AND every other scanline.
                yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
                if (j % 2 == 0 && index % 2 == 0) {
                    yuv420sp[uvIndex++] = (byte)((V<0) ? 0 : ((V > 255) ? 255 : V));
                    yuv420sp[uvIndex++] = (byte)((U<0) ? 0 : ((U > 255) ? 255 : U));
                }

                index ++;
            }
        }
    }
    private byte [] getNV21(int inputWidth, int inputHeight, Bitmap scaled) {

        int [] argb = new int[inputWidth * inputHeight];

        scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);

        byte [] yuv = new byte[inputWidth*inputHeight*3/2];
        encodeYUV420SP(yuv, argb, inputWidth, inputHeight);
        scaled.recycle();

        return yuv;
    }
    private void Prepare()
    {
        try {
            mBufferInfo = new MediaCodec.BufferInfo();

            mediaCodec = MediaCodec.createEncoderByType("video/avc");
            mediaFormat = MediaFormat.createVideoFormat("video/avc", this.width, this.height);
            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, CalcBitRate(0.109)/*16000000*/);
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, this.frameRate);

            /*String colors="";
            for(int i=0;i<mediaCodec.getCodecInfo().getCapabilitiesForType("video/avc").colorFormats.length;i++)
            {
                colors=colors+ String.valueOf(mediaCodec.getCodecInfo().getCapabilitiesForType("video/avc").colorFormats[i])+"\r\n";
            }
            Log.d(TAG, "colors: "+colors);
            2130706944
            2130708361
            2130706944
            19
            6
            11
            16*/
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
                //mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities./*COLOR_FormatYUV420SemiPlanar*/COLOR_FormatYUV420Planar);
                mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_Format32bitARGB8888);
            }else{
                mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
            }
            //2130708361, 2135033992, 21

            mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, /*IFRAME_INTERVAL*/1);

            /*final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE_AUDIO, 8, 1);
            audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_MONO);
            audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, 64000);
            audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);*/

            mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mediaCodec.start();

            /*mediaCodecForAudio = MediaCodec.createEncoderByType(MIME_TYPE_AUDIO);
            mediaCodecForAudio.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
            mediaCodecForAudio.start();*/

            try {
                String outputPath = new File(Environment.getExternalStorageDirectory(),
                        "test.mp4").toString();
                mediaMuxer = new MediaMuxer(outputPath/*"/sdcard/Download/test.mp4"*/, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            } catch (IOException e)
            {
                Log.d(TAG, "MediaMuxer file error: "+ e.getMessage());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void Encode(Bitmap  frame)
    {
        int inputBufIndex = mediaCodec.dequeueInputBuffer(55000);
        if (inputBufIndex >= 0)
        {
            //byte[] input = getNV21(this.width, this.height, frame);
            final ByteBuffer inputBuffer = mediaCodec.getInputBuffers()[inputBufIndex];
            inputBuffer.clear();
            int[] argb=new int[this.width*this.height];
            frame.getPixels(argb, 0, this.width, 0, 0, this.width, this.height);
            inputBuffer.asIntBuffer().put(argb);
            //inputBuffer.put(input);
            mediaCodec.queueInputBuffer(inputBufIndex, 0, /*input.length*/this.width*this.height*4,
                    computePresentationTime(this.frameIndex), 0);
            this.frameIndex++;
        }

        MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
        int encoderStatus = mediaCodec.dequeueOutputBuffer(mBufferInfo, 55000);
        switch(encoderStatus)
        {
            case MediaCodec.INFO_TRY_AGAIN_LATER:
                break;
            case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                MediaFormat newFormat = mediaCodec.getOutputFormat();
                if(newFormat!=null) {
                    vTrackIndex = mediaMuxer.addTrack(newFormat);
                    mediaMuxer.start();
                }
                break;
            default:
        }
        if(encoderStatus>-1) {
            ByteBuffer encodedData = mediaCodec.getOutputBuffers()[encoderStatus];
            if(encodedData!=null)
            {
                encodedData.position(mBufferInfo.offset);
                encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
                mediaMuxer.writeSampleData(vTrackIndex, encodedData, mBufferInfo);
                mediaCodec.releaseOutputBuffer(encoderStatus, false);
            }
        }
    }
    private void FinishRecord()
    {
        if (mediaCodec != null) {

            mediaCodec.stop();
            //mediaCodec.release();
            //mediaCodec = null;
        }
        if (mediaMuxer != null) {
            mediaMuxer.stop();
            mediaMuxer.release();
            mediaMuxer = null;
        }
        if (mediaCodec != null) {

            //mediaCodec.stop();
            mediaCodec.release();
            mediaCodec = null;
        }
        Log.d(TAG, "stop encoding");
    }
    @Override
    public void run()
    {
        Bitmap  frame=null;
        Prepare();
        for(;;)
        {
            if(finish==true)
            {
                FinishRecord();
                return;
            }
            try {
                frame=this.dataBuffer.take();
            } catch (InterruptedException e) {
                Log.d(TAG, "BlockingQueue::take error: "+ e.getMessage());
            }
            if(frame!=null)
            {
                this.Encode(frame);
                Log.d("frame_size: ", String.valueOf(frame.getByteCount()));
                //this.dataBuffer.remove(frame);
                frame.recycle();
                frame=null;
            }
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                Log.d(TAG,"sleep error "+ e.getMessage());
            }
        }
    }
}
👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Підписатись на коментарі