Der H. 264 avc-codiertes video von MediaCodec in Android kann nicht gespielt werden

HINTERGRUND:

Arbeite ich an der Umsetzung einer Rebe wie video-recorder für zwei Tage. Zuerst versuchte ich den MediaRecorder. Aber das video, das ich brauchen kann aus, indem Sie kleine video-clips. Diese Klasse kann nicht verwendet werden, um aufzuzeichnen einen kurzen video-clip. Dann fand ich den MediaCodec, FFmpeg und JavaCV. FFmpeg und JavaCV dieses problem lösen könnte. Aber ich habe zu kompilieren meines Projekts mit viele library-Dateien. Es erzeugt eine sehr große APK-Datei. Also ich bevorzuge die Umsetzung von MediaCodec, obwohl diese Klasse kann nur verwendet werden, nachdem Android 4.1. 90% Prozent der Benutzer zufrieden sein werden.

ERGEBNIS:

Habe ich endlich die kodierte Datei, aber es kann nicht gespielt werden. Ich habe die Informationen von FFprobe, das Ergebnis ist, wie:

Input #0, h264, aus " test.mp4':
Dauer: N/A bitrate: N/A
Stream #0:0: Video: h264 (Baseline), yuv420p, 640x480, 25 fps, 25 tbr, 1200k tbn, 50 tbc

Ich weiß nicht viel über den Mechanismus der H. 264 Codierung.

CODE:

Modifiziert von diesem link

public class AvcEncoder {

private static String TAG = AvcEncoder.class.getSimpleName();

private MediaCodec mediaCodec;
private BufferedOutputStream outputStream;
private int mWidth, mHeight;
private byte[] mDestData;

public AvcEncoder(int w, int h) {

    mWidth = w;
    mHeight = h;
    Log.d(TAG, "Thread Id: " + Thread.currentThread().getId());

    File f = new File("/sdcard/videos/test.mp4");

    try {
        outputStream = new BufferedOutputStream(new FileOutputStream(f));
        Log.i("AvcEncoder", "outputStream initialized");
    } catch (Exception e) {
        e.printStackTrace();
    }

    try {
        mediaCodec = MediaCodec.createEncoderByType("video/avc");
    } catch (IOException e) {
        //TODO Auto-generated catch block
        e.printStackTrace();
    }
    MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", w,
            h);
    mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2000000);
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
    //mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
    //MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
    mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);

    mDestData = new byte[w * h
            * ImageFormat.getBitsPerPixel(ImageFormat.YV12) / 8];
    mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
    mediaCodec.configure(mediaFormat, null, null,
            MediaCodec.CONFIGURE_FLAG_ENCODE);
    mediaCodec.start();
}

public void close() {
    try {
        mediaCodec.stop();
        mediaCodec.release();
        mediaCodec = null;

        //outputStream.flush();
        outputStream.close();
    } catch (IOException e) {

    }
}

public void offerEncoder(byte[] input) {
    try {
        CameraUtils.transYV12toYUV420Planar(input, mDestData, mWidth,
                mHeight);
        ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
        ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
        int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);

        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(mDestData);
            mediaCodec.queueInputBuffer(inputBufferIndex, 0,
                    mDestData.length, 0, 0);
        }

        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,
                0);

        while (outputBufferIndex >= 0) {
            ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
            byte[] outData = new byte[bufferInfo.size];
            outputBuffer.get(outData);
            try {
                outputStream.write(outData, 0, outData.length);

            } catch (Exception e) {
                Log.d("AvcEncoder", "Outputstream write failed");
                e.printStackTrace();
            }
            //Log.i("AvcEncoder", outData.length + " bytes written");

            mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
            outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,
                    0);

        }
    } catch (Throwable t) {
        t.printStackTrace();
    }
}
}

Aufrufen dieser Klasse von Kamera startPreview:

private void startPreview() {
    if (mCamera == null) {
        return;
    }
    try {
        mCamera.setPreviewDisplay(mSurfaceView.getHolder());
        Parameters p = mCamera.getParameters();
        Size s = p.getPreviewSize();
        int len = s.width * s.height
                * ImageFormat.getBitsPerPixel(p.getPreviewFormat()) / 8;
        mAvcEncoder = new AvcEncoder(s.width, s.height);
        mCamera.addCallbackBuffer(new byte[len]);
        mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() {

            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                mAvcEncoder.offerEncoder(data);
                mCamera.addCallbackBuffer(data);
            }
        });
        mCamera.startPreview();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Schließen, wenn release Kamera:

private void releaseCamera() {
    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
    if (mAvcEncoder != null) {
        mAvcEncoder.close();
    }
}
InformationsquelleAutor James Zhao | 2015-06-07
Schreibe einen Kommentar