Кодирование видео в 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()); } } } }
Немає коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів