从视频中获取帧 Android

12

我想从视频中获取帧数...我正在使用以下代码:

package com.vidualtest;

import java.io.File;
import java.io.FileDescriptor;

import android.app.Activity;
import android.graphics.Bitmap;
import android.media.MediaMetadataRetriever;
import android.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;

public class VidualTestActivity extends Activity {
/** Called when the activity is first created. */
File file;
ImageView img;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);


    img = (ImageView) findViewById(R.id.img);

    File sdcard = Environment.getExternalStorageDirectory();
    file = new File(sdcard, "myvid.mp4");

    MediaMetadataRetriever retriever = new MediaMetadataRetriever();

    try {
        retriever.setDataSource(file.getAbsolutePath());

        img.setImageBitmap(retriever.getFrameAtTime(10000,MediaMetadataRetriever.OPTION_CLOSEST));


    } catch (IllegalArgumentException ex) {
        ex.printStackTrace();
    } catch (RuntimeException ex) {
        ex.printStackTrace();
    } finally {
        try {
            retriever.release();
        } catch (RuntimeException ex) {
        }
    }


}

在getFrameAtTime()函数中,我传入不同的静态时间,如10000、20000毫秒等,但是我仍然在不同的时间内从视频中获取到相同的帧。我的目标是以不同的时间间隔获取不同的帧。

请帮助我解决问题,谢谢!


你的代码运行太慢了,每帧需要1秒钟。你找到更好的解决方案了吗? - Nativ
还没有,伙计!实际上我也在寻找优化解决方案。 - Rahul Upadhyay
1
所以请看下面我的解决方案! - Nativ
@RahulUpadhyay,你解决了你的问题吗? - dipali
6个回答

37

时间偏移参数单位为微秒,而非毫秒。因此,将您的时间偏移乘以1000,它应该可以正确工作。

感谢 Google 没有在文档中明确指定这一点。


4

如果您的视频长度为10秒,如果您想在1秒后获取一帧,则将其增加1000000,表示1秒后。

我已将图像视图的ID存储在一个数组中。

int[] ids_of_images = new int[]{R.id.img,R.id.img2,R.id.img3,R.id.img4,R.id.img5};
looper =1000000;

然后

 for(int i=0 ;i <10; i++)
        {
            ImageView imageView = (ImageView)findViewById(ids_of_images[i]);

            imageView.setImageBitmap(retriever.getFrameAtTime(looper,MediaMetadataRetriever.OPTION_CLOSEST));

            looper +=1000000;
        }

我已经测试过它了,它能够运行。我创建了十个ImageView并按照上述方式读取帧。


1
好的逻辑。我会尝试。 - Rahul Upadhyay
负面投票的原因是什么?请详细解释。 - Zar E Ahmer

2
尝试使用微秒,它应该可以工作!

1

使用jCodec库,我能够通过以下代码高效地获取视频中的所有帧:

private class Decoder extends AsyncTask<File, Integer, Integer> {
    private static final String TAG = "DECODER";

    protected Integer doInBackground(File... params) {
        FileChannelWrapper ch = null;
        try {
            ch = NIOUtils.readableFileChannel(params[0]);
            FrameGrab frameGrab = new FrameGrab(ch);
            MediaInfo mi = frameGrab.getMediaInfo();
            Bitmap frame = Bitmap.createBitmap(mi.getDim().getWidth(), mi.getDim().getHeight(), Bitmap.Config.ARGB_8888);

            for (int i = 0; !flag; i++) {

                frameGrab.getFrame(frame);
                if (frame == null)
                    break;
                OutputStream os = null;
                try {
                    os = new BufferedOutputStream(new FileOutputStream(new File(params[0].getParentFile(), String.format("img%08d.jpg", i))));
                    frame.compress(CompressFormat.JPEG, 90, os);
                } finally {
                    if (os != null)
                        os.close();
                }
                publishProgress(i);

            }
        } catch (IOException e) {
            Log.e(TAG, "IO", e);
        } catch (JCodecException e) {
            Log.e(TAG, "JCodec", e);
        } finally {
            NIOUtils.closeQuietly(ch);
        }
        return 0;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        progress.setText(String.valueOf(values[0]));
    }
}

1
public Bitmap getFrameAtTime (long timeUs, int option)

有人遗漏了文档说明,该方法中的timeUs应该是微秒而不是毫秒。你可以在其他方法文档中找到提示:

timeUs long: 以微秒为单位的时间位置

请确保将您的毫秒数乘以1000。

retriever.getFrameAtTime(1000000, Int) // returns the frame after one second

0

我认为getFrameAt()函数返回最接近你指定的时间间隔的帧。因此,如果最接近这两个时间间隔的帧是相同的,则将1000或1500作为时间(以毫秒为单位)进行指定可能会返回同一帧。要获取帧数,您可能需要获取重复的帧,然后通过检查几个像素来检查它们是否不同。但是,您必须确保不错过任何帧。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接