使用AndroidFrameConverter将javacv帧转换为位图

3

我正在尝试使用javacv AndroidFrameConverter将大小为1280x720的帧转换为位图,但转换时间很长。这是转换的示例代码。

FrameGrabber grabber = new FFmpegFrameGrabber(videoUrl);
frame = grabber.grab();
AndroidFrameConverter converter = new AndroidFrameConverter();
Bitmap originalBitmap = converter.convert(frame);

有没有比这更快的解决方案?

位图转换是一项繁重的任务,因此转换需要时间。问题在于,在将其转换为位图后,您需要执行什么操作? - Muhammad Umair Shafique
我想在位图转换后绘制一些覆盖层。 - Zaid Bin Tariq
Javacv提供了FrameFilter这个工具,可以通过ffmpeg命令来绘制覆盖层而无需转换为位图。我添加了FrameFilter的示例代码,您可以使用它来实现所需的结果。 - Muhammad Umair Shafique
2个回答

2
FrameGrabber.grab() 返回的帧是 javacv 特有的,Bitmap 则是 Android 特有的。我怀疑两者之间没有更快的转换方法,因为它们彼此不知道,并且都被优化用于自身的用途,它们无法优化两种数据格式之间的转换过程。
每一帧传输 1280 * 720 * 4 字节,大约是 3.6 MB,对于移动设备来说非常庞大,尤其是考虑到内存分配的情况。
除非使用其他东西替换 javacv,否则我不认为您会找到另一个转换工具 - 想象不出一种专门用于将 javacv 的 Frame 转换为 Android Bitmap 的工具。
此外,AndroidFrameConverter.convert() 已经非常聪明 - 它仅在第一次或规格(如大小等)发生更改时才创建 Bitmap,然后只复制字节。
所以幸运的是,它可以重用已创建的 Bitmap 实例,FFmpegFrameGrabber 也具有此功能,因此在第一次运行时,它们将各自创建一个适当的对象,但在第二个帧上应该重用它们拥有的对象。这样,至少不会发生不必要的内存分配,因为这会影响移动设备的性能。这意味着转换许多帧平均应该比仅转换一帧更快 - 只需不要为每个帧创建新的抓取器和转换器实例即可。
使用 GPU 并行化可能是可能的 - 手动创建一个 Bitmap,将 Frame 的缓冲区划分并以并行方式设置 Bitmap 的像素。我自己从未做过这样的事情,所以无法发表更多评论。只需记住,并行算法有自己的开销,并不总是比顺序算法更快。我也不确定 GPU 编程的可移植性如何。使用 CPU 进行并行化不值得尝试 - 当前设备有多少核心?4 个?开销应该比收益更大。

1
你可以使用这段代码,并根据需要更改过滤器。
public class FilterAsync extends AsyncTask {

    private FFmpegFrameGrabber VIDEO_GRABBER;
    private FFmpegFrameRecorder videoRecorder;
    private File file = new File(Environment.getExternalStorageDirectory() + "/Download/Abc.mp4");
    private Context mContext;
    private FFmpegFrameFilter filter;
    private boolean isTrue = false;
    private ArrayList<String> videoPaths;
    private File myDirectory;


    public FilterAsync(Context context) {
        mContext = context;
        VIDEO_GRABBER = new FFmpegFrameGrabber(file);
        myDirectory = new File(Environment.getExternalStorageDirectory() + "/Folder/");
        if (!myDirectory.exists()) {
            myDirectory.mkdirs();
        }
        videoPaths = new ArrayList<>();
    }


    @Override
    protected void onPreExecute() {
        super.onPreExecute();

    }

    @Override
    protected Object doInBackground(Object[] params) {
        Frame tempVideoFrame;
        try {
            VIDEO_GRABBER.start();
            initVideoRecorder(myDirectory + "/video" + System.currentTimeMillis() + ".mp4");
            filter.start();
            while (VIDEO_GRABBER.grab() != null) {
                tempVideoFrame = VIDEO_GRABBER.grabImage();
                if (tempVideoFrame != null) {
                    filter.push(tempVideoFrame);
                    tempVideoFrame = filter.pull();
                    videoRecorder.record(tempVideoFrame);
                }
            }
            videoRecorder.stop();
            filter.stop();
            videoRecorder.release();
            VIDEO_GRABBER.stop();
            VIDEO_GRABBER.release();
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        } catch (FrameRecorder.Exception e) {
            e.printStackTrace();
        } catch (FrameFilter.Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    @Override
    protected void onPostExecute(Object o) {
        super.onPostExecute(o);
    }


    private void initVideoRecorder(String path) {
        try {
            filter = new FFmpegFrameFilter("transpose=clock ,crop=w=640:h=480:x=0:y=0", VIDEO_GRABBER.getImageWidth(), VIDEO_GRABBER.getImageHeight());

            videoRecorder = FFmpegFrameRecorder.createDefault(path, VIDEO_GRABBER.getImageWidth(), VIDEO_GRABBER.getImageHeight());
           videoRecorder.setAudioChannels(VIDEO_GRABBER.getAudioChannels());
            videoRecorder.start();
        } catch (FrameRecorder.Exception e) {
            e.printStackTrace();
        }
    }
}

它会给出警告和异常:从yuv420p到bgr24没有找到加速的色彩空间转换。 - Zaid Bin Tariq
你的端可能存在问题,因为在我的端上它完美地运行。请向我展示你的javacv gradle依赖项。 - Muhammad Umair Shafique
compile 'org.bytedeco:javacpp:1.1' compile 'org.bytedeco:javacv:1.1' compile 'org.bytedeco.javacpp-presets:ffmpeg:2.8.1-1.1' compile 'org.bytedeco.javacpp-presets:ffmpeg:2.8.1-1.1:android-arm' compile 'org.bytedeco.javacpp-presets:ffmpeg:2.8.1-1.1:android-x86' compile 'org.bytedeco.javacpp-presets:opencv:3.0.0-1.1:android-arm' compile 'org.bytedeco.javacpp-presets:opencv:3.0.0-1.1:android-x86' - Zaid Bin Tariq
编译 'org.bytedeco:javacv:1.1' 这行代码为什么出现了两次? - Muhammad Umair Shafique
我可以使用这个命令将图像标记设置为位图吗? 我正在使用相同的东西,但是当我使用"ImageOverlaybitmap"时,一切都正常,但处理速度变成了1分钟视频需要12分钟。 - Ahmad Arslan
显示剩余4条评论

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