Выбор видео, декодирование, изменение его fps, кодирование и сохранение с использованием mediacodec - PullRequest
0 голосов
/ 09 июня 2018

Хотел бы выбрать видео с устройства и декодировать его, чтобы изменить частоту кадров, а затем кодировать и сохранить его на устройстве.Как это возможно с помощью MediaCodec?Прошел много документации, но не смог найти метод.У меня есть следующий код для декодирования.Будет ли это полезным для моей цели.Если да, то как использовать эти декодированные данные, чтобы сохранить их с измененным fps.

 MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", 1080, 720);
            mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 2500000);
            mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
            try {
                decoder = MediaCodec.createDecoderByType("video/avc");
            } catch (IOException e) {
                Log.d("Error", "Fail to create MediaCodec: " + e.toString());
            }



            ///Commenting for testing...
            /*
            // Pass the decoded data to the surface to display
            decoder.configure(mediaFormat, null, null, 0);
            //decoder.configure(mediaFormat, null, null, 0);
            decoder.start();

            */
            ///Commenting for testing...



            // new BufferInfo();

            ByteBuffer[] inputBuffers = decoder.getInputBuffers();
            ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
            if (null == inputBuffers) {
                Log.d("Error", "null == inputBuffers");
            }
            if (null == outputBuffers) {
                Log.d("Error", "null == outbputBuffers 111");
            }

            FileInputStream file = null;
            try {
                file = new FileInputStream(data.getData().getPath().toString());
            } catch (FileNotFoundException e) {
                Log.d("Error", "open file error: " + e.toString());
                return;
            }
            int read_size = -1;
            int mCount = 0;

            for (; ; ) {
                byte[] h264 = null;
                try {
                    byte[] length_bytes = new byte[4];
                    read_size = file.read(length_bytes);
                    if (read_size < 0) {
                        Log.d("Error", "read_size<0 pos1");
                        break;
                    }
                    int byteCount = bytesToInt(length_bytes, 0);

                    //Changed to .length
                    //int byteCount=length_bytes.length;

                    Log.d("Error", "byteCount: " + byteCount);

                    h264 = new byte[byteCount];
                    read_size = file.read(h264, 0, byteCount);
                    // Log.d("Error", "read_size: " + read_size);
                    if (read_size < 0) {
                        Log.d("Error", "read_size<0 pos2");
                        break;
                    }
                    // Log.d("Error", "pos: " + file.)
                } catch (IOException e) {
                    Log.d("Error", "read_size 2: " + read_size);
                    Log.d("Error", "e.toStrinig(): " + e.toString());
                    break;
                }

                int inputBufferIndex = decoder.dequeueInputBuffer(-1);
                if (inputBufferIndex >= 0) {
                    ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                    inputBuffer.clear();
                    inputBuffer.put(h264);
                    // long sample_time = ;
                    decoder.queueInputBuffer(inputBufferIndex, 0, h264.length, mCount * 1000000 / 20, 0);
                    ++mCount;
                } else {
                    Log.d("Error", "dequeueInputBuffer error");
                }

                ByteBuffer outputBuffer = null;
                MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
                int outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);
                while (outputBufferIndex >= 0) {
                    outputBuffer = outputBuffers[outputBufferIndex];
                    decoder.releaseOutputBuffer(outputBufferIndex, true);
                    outputBufferIndex = decoder.dequeueOutputBuffer(bufferInfo, 0);
                }

                // Pass the decoded data to the surface to display
                decoder.configure(mediaFormat,mPreview.getHolder().getSurface() , null, 0);
                //decoder.configure(mediaFormat, null, null, 0);


                decoder.start();

                if (outputBufferIndex >= 0) {
                    decoder.releaseOutputBuffer(outputBufferIndex, false);
                } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                    outputBuffers = decoder.getOutputBuffers();
                    Log.d("Error", "outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED");
                } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    // Subsequent data will conform to new format.
                    Log.d("Error", "outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED");
                }

                try {
                    Thread.sleep(1000/20);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }




            }
    }
}
public int bytesToInt(byte[] src, int offset) {
    int value;
    value = (int) ((src[offset] & 0xFF)
            | ((src[offset+1] & 0xFF)<<8)
            | ((src[offset+2] & 0xFF)<<16)
            | ((src[offset+3] & 0xFF)<<24));
    return value;
}

1 Ответ

0 голосов
/ 10 июня 2018

Вы можете взглянуть на DecodeEditEncode , отличную отправную точку для декодирования и перекодирования с использованием поверхностей (выходная поверхность для декодера -> входная поверхность для кодера).

Взятьособенно обратите внимание на этот метод

private void editVideoData(VideoChunks inputData, MediaCodec decoder,
            OutputSurface outputSurface, InputSurface inputSurface, MediaCodec encoder,
            VideoChunks outputData)

Рабочий процесс, которому вы должны следовать, похож на приведенный ниже:

  • Извлечение видеодорожки (MediaExtractor)

  • Подача входных буферов декодера

  • рендеринг декодированного кадра на поверхность

  • При визуализации кодер получит кадр (Вы также должны установить метку времени)
  • Используйте MediaMuxer для мультиплексирования кадра кодера с аудиодорожкой.

Дополнительные ссылки : некоторые примеры

ExtractDecodeEditEncodeMuxTest

VideoResample.java (очень интересно)

...