Android FFMPEG - 低FPS&文件大小很大

时间:2018-05-02 21:54:00

标签: java android ffmpeg

我是Android应用开发的新手,我被要求制作视频分割器应用。我正在尝试使用FFMPEG,但库大小很大,使得.APK文件为140MB。我怎么解决这个问题?类似的应用程序大小约为15MB。

此外,当尝试将30秒长的视频分成两部分时,帧速率从~30FPS开始并随着时间的推移下降到2.2FPS左右。我怎么解决这个问题?这是我目前的代码:

package splicer.com.splicer;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.media.MediaMetadataRetriever;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.FFmpeg;
import com.github.hiteshsondhi88.libffmpeg.LoadBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegNotSupportedException;

public class MainActivity extends AppCompatActivity {

    private Button button;
    private TextView textView;
    private FFmpeg ffmpeg;

    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ffmpeg = FFmpeg.getInstance(getApplicationContext());
        try {
            ffmpeg.loadBinary(new LoadBinaryResponseHandler() {

                @Override
                public void onStart() {}

                @Override
                public void onFailure() {}

                @Override
                public void onSuccess() {}

                @Override
                public void onFinish() {}
            });
        } catch(FFmpegNotSupportedException e) {
            e.printStackTrace();
        }

        textView = (TextView) findViewById(R.id.textView);
        textView.setY(200);
        textView.setHeight(700);
        textView.setMovementMethod(new ScrollingMovementMethod());

        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                openGallery();
            }
        });
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public void openGallery() {
        if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String [] {Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
        }

        if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String [] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
        }

        Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(gallery, 100);
    }

    public String getRealPathFromURI(Context context, Uri contentUri) {
        Cursor cursor = null;
        try {
            String[] proj = { MediaStore.Images.Media.DATA };
            cursor = context.getContentResolver().query(contentUri,  proj, null, null, null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, final Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if(resultCode == RESULT_OK && requestCode == 100) {
            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
            try {
                retriever.setDataSource(getBaseContext(), intent.getData());
                String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                long splitCount = Long.valueOf(time) / 1000 / 15;
                if(splitCount > 1) {
                    final String path = getRealPathFromURI(getBaseContext(), Uri.parse(intent.getData().toString()));

                    for(int a = 0, start = 0; a < splitCount; ++a, start += 15) {
                        // I am only testing with .mp4s atm, this will change before production
                        final String targetPath = path.replace(".mp4", "_" + (a + 1) + ".mp4");

                        ffmpeg.execute(new String [] {
                                "-r",
                                "1",
                                "-i",
                                path,
                                "-ss",
                                String.valueOf(start),
                                "-t",
                                String.valueOf(start + 15),
                                "-r",
                                "24",
                                targetPath
                        }, new ExecuteBinaryResponseHandler() {
                            @Override
                            public void onStart() {}

                            @Override
                            public void onProgress(String message) {
                                textView.setText("onProcess: " + message);
                            }

                            @Override
                            public void onFailure(String message) {
                                textView.setText("onFailure: " + message + " --- " + path);
                            }

                            @Override
                            public void onSuccess(String message) {
                                textView.setText("onSuccess:" + message);
                                MediaScannerConnection.scanFile(getBaseContext(),
                                new String [] { targetPath }, null,
                                new MediaScannerConnection.OnScanCompletedListener() {
                                    public void onScanCompleted(String path, Uri uri) {}
                                });
                            }

                            @Override
                            public void onFinish() {}
                        });
                    }
                }
            } catch(Exception e) {
                e.printStackTrace();
            } finally {
                retriever.release();
            }
        }
    }
}

我不相信这里的一切都尽可能最优,但我只是想在此刻证明这个概念。在正确的方向上任何帮助都会很棒,谢谢!

0 个答案:

没有答案