15

I want to create an android application which can locate a video file (which is more than 300 mb) and compress it to lower size mp4 file.

i already tried to do it with this

This tutorial is a very effective since you 're compressing a small size video (below than 100 mb)

So i tried to implement it using JNI .

i managed to build ffmpeg using this

But currently what I want to do is to compress videos . I don't have very good knowledge on JNI. But i tried to understand it using following link

If some one can guide me the steps to compress video after open file it using JNI that whould really great , thanks

Akash Singh
  • 5,171
  • 2
  • 26
  • 55
Mr.G
  • 1,275
  • 1
  • 18
  • 48

1 Answers1

6

Assuming you've got the String path of the input file, we can accomplish your task fairly easily. I'll assume you have an understanding of the NDK basics: How to connect a native .c file to native methods in a corresponding .java file (Let me know if that's part of your question). Instead I'll focus on how to use FFmpeg within the context of Android / JNI.

High-Level Overview:

#include <jni.h>
#include <android/log.h>
#include <string.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"

#define LOG_TAG "FFmpegWrapper"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)


void Java_com_example_yourapp_yourJavaClass_compressFile(JNIEnv *env, jobject obj, jstring jInputPath, jstring jInputFormat, jstring jOutputPath, jstring JOutputFormat){
  // One-time FFmpeg initialization
  av_register_all();
  avformat_network_init();
  avcodec_register_all();

  const char* inputPath = (*env)->GetStringUTFChars(env, jInputPath, NULL);
  const char* outputPath = (*env)->GetStringUTFChars(env, jOutputPath, NULL);
  // format names are hints. See available options on your host machine via $ ffmpeg -formats
  const char* inputFormat = (*env)->GetStringUTFChars(env, jInputFormat, NULL);
  const char* outputFormat = (*env)->GetStringUTFChars(env, jOutputFormat, NULL);

  AVFormatContext *outputFormatContext = avFormatContextForOutputPath(outputPath, outputFormat);
  AVFormatContext *inputFormatContext = avFormatContextForInputPath(inputPath, inputFormat /* not necessary since file can be inspected */);

  copyAVFormatContext(&outputFormatContext, &inputFormatContext);
  // Modify outputFormatContext->codec parameters per your liking
  // See http://ffmpeg.org/doxygen/trunk/structAVCodecContext.html

  int result = openFileForWriting(outputFormatContext, outputPath);
  if(result < 0){
      LOGE("openFileForWriting error: %d", result);
  }

  writeFileHeader(outputFormatContext);

  // Copy input to output frame by frame
  AVPacket *inputPacket;
  inputPacket = av_malloc(sizeof(AVPacket));

  int continueRecording = 1;
  int avReadResult = 0;
  int writeFrameResult = 0;
  int frameCount = 0;
  while(continueRecording == 1){
      avReadResult = av_read_frame(inputFormatContext, inputPacket);
      frameCount++;
      if(avReadResult != 0){
        if (avReadResult != AVERROR_EOF) {
            LOGE("av_read_frame error: %s", stringForAVErrorNumber(avReadResult));
        }else{
            LOGI("End of input file");
        }
        continueRecording = 0;
      }

      AVStream *outStream = outputFormatContext->streams[inputPacket->stream_index];
      writeFrameResult = av_interleaved_write_frame(outputFormatContext, inputPacket);
      if(writeFrameResult < 0){
          LOGE("av_interleaved_write_frame error: %s", stringForAVErrorNumber(avReadResult));
      }
  }

  // Finalize the output file
  int writeTrailerResult = writeFileTrailer(outputFormatContext);
  if(writeTrailerResult < 0){
      LOGE("av_write_trailer error: %s", stringForAVErrorNumber(writeTrailerResult));
  }
  LOGI("Wrote trailer");
}

For the full content of all the auxillary functions (the ones in camelCase), see my full project on Github. Got questions? I'm happy to elaborate.

dbro
  • 1,718
  • 1
  • 20
  • 34
  • i'll try it and let u know , can u send me ur mail address, – Mr.G Dec 23 '13 at 05:30
  • I have downloaded your sample application from GIT but it that seems it works for only android 4.4 – Mr.G Dec 23 '13 at 07:18
  • as u said i know "How to connect a native .c file to native methods in a corresponding .java file" i want to know the native c code to compress video, i tried to execute ut Github project but it seems that it works on android 4.4 – Mr.G Dec 23 '13 at 11:04
  • The GitHub project I linked is an experiment with [MediaCocec](http://developer.android.com/reference/android/media/MediaCodec.html) and FFmpeg, and that's where the Android 4.3 requirement comes from. The core files you want to include in your app are the `jni/` folder and `FFmpegWrapper.java`. You'll modify FFmpegWrapper.c and FFmpegWrapper.java to only expose the one function I included in my response. Also see my notes on [building FFmpeg for Android](https://github.com/OnlyInAmerica/FFmpeg-Android) when you need to configure the FFmpeg libraries for your needs. – dbro Dec 27 '13 at 01:50
  • i tried to excute program i recieve this error in my log-cat Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1936]: 138 could not load needed library 'libavformat-55.so' for 'libFFmpegWrapper.so' (load_library[1091]: Library 'libavformat-55.so' not found) But the libavcodec-55.so is available in the lib folder – Mr.G Dec 30 '13 at 05:19
  • Have you also copied [Android.mk](https://github.com/OnlyInAmerica/FFmpegTest/blob/365fdd214f5749400107924a91b23f1580244490/jni/Android.mk)? What happens when you run `ndk-build` in your terminal from the project's jni directory? – dbro Dec 30 '13 at 18:48
  • yeah . i copied Android.mk file and ndk-build runs and it will build app the .so files . So i think thr is an issue with linking files . Also i tried to run ur sample application . it gives same error. – Mr.G Dec 31 '13 at 06:36
  • Can you post the source to your application? – dbro Jan 03 '14 at 17:55
  • i have made a sample application to run ur native source . but it gives that error , which i mentioned above . i f u send me mail address i can send you the source code' – Mr.G Jan 06 '14 at 08:17
  • Put it up on Github so we can share the solution with everyone here. – dbro Jan 06 '14 at 20:54
  • sure. i'll add it to github. – Mr.G Jan 07 '14 at 05:25
  • @dbro How can I call this function with desired parameters ? I know how to call it.. but specifically doubt about passing params. – SachinGutte Feb 15 '14 at 08:07
  • I spend a lot of time and later could not get past the error undefined reference to 'avformat_new_stream' 'avformat_close_input' and some more functions. I could see these functions were defined in libavformat/utils.c but when I try to import, the compiler cannot find utils.c and I am still unable to compile the code. – JaydeepW Feb 20 '14 at 12:45
  • @dbro : Hello, " How to connect a native .c file to native methods in a corresponding .java file" is my issue, would you like to help me? I know `Java_com_example_yourapp_yourJavaClass_compressFile` means what. But I don't know how to define in Java class and MK file to load it, call this method ... – Huy Tower Mar 24 '14 at 02:20
  • 2
    It just copies video not compresses the size. – Biraj Zalavadia May 06 '15 at 05:58
  • @BirajZalavadia to compress you modify AVFormatContext *outputFormatContext after it's initialized with `copyAVFormatContext`. See the comment in the code I embedded for a helpful link to the FFmpeg docs. – dbro May 06 '15 at 16:12
  • I think we need to know how to compress the video.Which method can do it? – wangqi060934 Jul 23 '15 at 10:48
  • in this method "inputformat" and "outputformat" which value passed from java class ? – axita.savani Oct 14 '19 at 04:55