-3

Would like to pick a video from the device and decode it inorder to change its frame rate and then encode and save it to the device. How is this possible using MediaCodec? Went through many documentations, but couldn't find a method. I have the following code for decoding. Will it be of any good for my purpose. If yes how to use that decoded data to save it with changed 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;
}
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
  • decode, resample, encode, save. That is at least 4 questions. Stack-overflow works best when there is one question per post, otherwise its too much work for a volunteer to give an answer thats valuable to the community. – szatmary Jun 09 '18 at 17:19
  • If we ask this as 4 questions, we will get different kinds of answer. I’m looking for a complete solution for all 4 of these. – Cognifox Technologies Jun 09 '18 at 17:28
  • Stackoverflow is not a code writing service. Its is a resource to help YOU write code. Nobody is going to provide you with a complete solution here. – szatmary Jun 09 '18 at 17:31
  • Don’t bother about my question if you can’t answer. – Cognifox Technologies Jun 09 '18 at 17:32
  • I just included the different steps of my need in my question instead of asking a wide question like, how to change the FPS of a local video using mediacodec. There are several wide questions like this on stackoverflow and I have seen the complete solutions. So please don’t bother much........ – Cognifox Technologies Jun 09 '18 at 17:36

1 Answers1

2

You can take a look at DecodeEditEncode, a great starting point for decoding and re-encoding using surfaces (output surface for decoder -> input surface for encoder).

Take a look especially at this method

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

The working flow that you have to follow is similar to bellow:

  • Extract video track (MediaExtractor)

  • Feed the decoder input buffers

  • render the decoded frame to the surface

  • When rendered, the encoder will get the frame (you have to set timestamp too)
  • Use MediaMuxer to mux the encoder frame with audio track.

Extra links : some examples

ExtractDecodeEditEncodeMuxTest

VideoResample.java (very interesting)

E.Abdel
  • 1,992
  • 1
  • 13
  • 24