wseemann / FFmpegMediaMetadataRetriever

FFmpegMediaMetadataRetriever provides a unified interface for retrieving frame and meta data from an input media file.
1.73k stars 387 forks source link

A/libc: Fatal signal 6 (SIGABRT) when using FFmpeg mediametadataretriever in android #214

Open taimoor1996 opened 5 years ago

taimoor1996 commented 5 years ago

I am using FFmpegMediaMetaDataRetriever for extracting frames in my android project. I want to extract frames after every 10 seconds. Here is the code of function extractFramesFromVideo in upload_media_screen.java fragment file: public void extractFramesFromVideo(Uri videoUri) { FFmpegMediaMetadataRetriever frameRetriever = new FFmpegMediaMetadataRetriever();

    frameRetriever.setDataSource(MainActivity.this,videoUri);

    long duration= Long.parseLong(frameRetriever.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION));

    long minute= duration / 60;
    long durationInSeconds= minute  * 60;

    int noOfFrames= (int) (durationInSeconds / 10);

    for (int count=1; count <= noOfFrames; ++count)
    {
        Bitmap frameBitmap = frameRetriever.getFrameAtTime(count * 10000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
        saveImage(frameBitmap, "frame-no" + count);
    }

}

It is used in function onActivityResult in MainActivity.java: @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent);

     Log.d("videoUri",requestCode+" "+resultCode);

     if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK)
     {
        Log.d("videoUri",requestCode+" "+resultCode);
        Uri videoUri = intent.getData();

        uploadMediaScreen = (upload_media_screen)
                getSupportFragmentManager().findFragmentById(R.id.upload_media_screen);

        uploadMediaScreen.extractFramesFromVideo(videoUri);
    }
}

The frames get saved by this method in upload_media_screen.java fragment file: private void saveImage(Bitmap finalBitmap, String image_name) { String root = Environment.getExternalStorageDirectory().toString(); File myDir = new File(root); myDir.mkdirs(); String fileName = "Image-" + image_name+ ".jpg"; File file = new File(myDir, fileName); if (file.exists()) file.delete(); Log.i("LOAD", root + fileName); try { FileOutputStream out = new FileOutputStream(file); finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } I can't see any frames in my phones gallery neither any error is showing up.

HBiSoft commented 4 years ago

Your problem is here:

for (int count=1; count <= noOfFrames; ++count){
    Bitmap frameBitmap = frameRetriever.getFrameAtTime(count * 10000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
    saveImage(frameBitmap, "frame-no" + count); 
}

You are continuously trying to get a frame even if it is still busy retrieving the current frame.

Instead, you should be doing this inside an AsyncTask and only start retrieving the next frame inside onPostExecute when the previous frame was retrieved successfully.

This is not an issue with the library, but instead the way that you have implemented it.

ShwetaChauhan18 commented 2 years ago

I have same issue and after some time ANR happens. I am trying to get a frame if it's still busy retrieving the current frame. I have to do this because for video seeker if user continuously change seekbar progress I need to show it video frame where seekbar is.

Any proper way for this type of issue??

HBiSoft commented 2 years ago

@ShwetaChauhan18 The proper way of doing what you want to do is using the MediaCodec API. You will have decode each frame, drop the frames you are not interested and send the ones you are interested in to a surface.

What you are trying to do with FFmpegMediaMetadataRetreiver is not a feasible option because it takes up to a few seconds to return the desired frame. Even if you get the frames on a background thread, there will always be a delay.

engrtaipu commented 1 year ago

@taimoor1996 have you got any solution for it. I am facing same issue. I have RTSP stream from IP camera.the app crashes with same error.kindly guide me.

bqfa commented 1 year ago

Your problem is here:

for (int count=1; count <= noOfFrames; ++count){
    Bitmap frameBitmap = frameRetriever.getFrameAtTime(count * 10000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
    saveImage(frameBitmap, "frame-no" + count); 
}

You are continuously trying to get a frame even if it is still busy retrieving the current frame.

Instead, you should be doing this inside an AsyncTask and only start retrieving the next frame inside onPostExecute when the previous frame was retrieved successfully.

This is not an issue with the library, but instead the way that you have implemented it.

Why this happens only in one device ? I tested in 16 devices and error occurs only in OPPO CPH2213 Android 13

HBiSoft commented 1 year ago

Why this happens only in one device ? I tested in 16 devices and error occurs only in OPPO CPH2213 Android 13

Add logs to make sure that your previous bitmap was retrieved successfully and do not continue until it has. If you continue to retrieve bitmaps witout the previous one finishing, you will eventually get this error. When and if you get this will depend on your device.

As mentioned in a previous comment, this is not the recommended way of retrieving multiple bitmaps from a video, especially when you need to display the bitmaps directly after "retrieving" them. But it's definitely possible if time is not an issue.