【问题标题】:Adding Video Visual Filter to mp4将视频视觉过滤器添加到 mp4
【发布时间】:2019-02-08 07:48:34
【问题描述】:

我正在尝试将visual filters 添加到Android 中的video。它应该看起来像 Instagram 的功能,在录制 video 后,您可以从列表中选择 visual filter 然后应用它。到目前为止,我发现的最好的是GPUImage,它有多个过滤器选项,但它只能用于图像。

录制视频后,我在temp 文件夹中创建了一个.mp4 文件,在上传之前,会打开与下图类似的屏幕。我需要创建一个类似的过滤器选项和过滤器添加。

是否有一些API 可以帮助我或者有人有源代码?

【问题讨论】:

标签: android video filter effects


【解决方案1】:

您必须重新编码 mp4 文件才能将过滤器应用于每一帧。我可以想到两种方法,但它们需要高级编程技能。我认为最简单的方法是 FFMPEG(如果要重新编码,请务必检查许可证)。 This link 可能会帮助您为 Android 编译它。完成后,查看 FFMPEG 文档和论坛以获取过滤器和覆盖。另一种(免费)方法是使用MediaCodec 重新编码您的视频,并使用 GL 着色器来操作您的帧。 Grafika 是一个可以为您提供必要工具的项目。此外,互联网上可能有预先构建的两种方式的库,请务必先使用给定的信息进行研究。

【讨论】:

  • 我已经在使用 FFMPEG 将 pcm 转换为 WAV,并且我已经看到了一些允许一些基本过滤器的方法,但更难的部分是您可以滚动的列表(如图所示)并选择过滤器,然后应用它。
  • 您应该能够从视频中抓取任何帧,将过滤器应用于图像并将其显示在您的 UI 中。不幸的是,我不能给你任何代码示例,但 FFMPEG 能够做到这一点。
  • 我会调查的
  • 是否有直接链接可以找到 FFmpeg 视觉过滤器?我能找到的只是裁剪和编辑过滤器
  • 尝试在网上搜索常见的效果类型。这是棕褐色的链接:stackoverflow.com/questions/30972646/…。但你可能想使用“鱼眼”或其他东西。
【解决方案2】:

你试过this one 吗?它使用 FFMPEG 来添加过滤器/裁剪和更多编辑功能,这可以作为一个库帮助你,也可以给你一个想法,它有一个使用这个库构建的演示应用程序,可在 play store here

【讨论】:

  • 您是否有任何示例如何保存保存在temp 文件夹中的输出 mp4 文件,例如添加了过滤器?因为我不太了解他们的文档。
【解决方案3】:

除了 FFMPEG 方法之外,我发现对自己有用的一种方法是使用 GLSurfaceView。这个想法是在 GLSurfaceView 上渲染视频并使用 openGL 渲染过滤器。查看this project

【讨论】:

  • 是否可以将输出文件保存到外部存储器,添加过滤器?
  • 是的,看看 grafika 项目,尤其是this one
【解决方案4】:

花了我一段时间,但我用FFmpeg 弄明白了。因为我的项目已经在使用bravobit FFmpeg (Bravobit ffmpeg),所以我决定坚持下去。我已经添加了创建它所需的所有代码,以防有人在同一个地方摔倒。

首先我必须创建一个Horizontal scrollview

<HorizontalScrollView
    android:layout_width="wrap_content"
    android:layout_height="150dp"
    android:layout_alignParentBottom="true"
    android:layout_alignParentStart="true"
    android:layout_gravity="center_vertical"
    android:layout_marginBottom="143dp"
    android:scrollbars="none">

    <LinearLayout
        android:id="@+id/filter_list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:orientation="horizontal"></LinearLayout>
</HorizontalScrollView>

并创建一个filter_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="95dp"
    android:layout_height="wrap_content"

    android:layout_marginLeft="4dp"
    android:layout_marginStart="4dp"
    android:orientation="vertical">

    <TextView
        android:id="@+id/filter_item_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="5dp"
        android:layout_marginTop="5dp"
        android:textColor="#ff0000"
        android:textStyle="bold"
        android:textSize="14dp" />


    <android.support.v7.widget.AppCompatImageView
        android:id="@+id/filter_item_image"
        android:layout_width="match_parent"
        android:layout_height="90dp"
        android:layout_below="@+id/filter_item_name"
        android:scaleType="centerCrop" />


</RelativeLayout>

接下来,我从视频File 中获取缩略图,并使用该缩略图调用方法:

shareToFragment.setThumbNailImage(getVideoThumbnail(cameraOutputFile.getPath()));

public static Bitmap getVideoThumbnail(String path) {
    Bitmap bitmap = null;

    FFmpegMediaMetadataRetriever fmmr = new FFmpegMediaMetadataRetriever();

    try {
        fmmr.setDataSource(path);

        final byte[] data = fmmr.getEmbeddedPicture();

        if (data != null) {
            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
        }

        if (bitmap == null) {
            bitmap = fmmr.getFrameAtTime();
        }
    } catch (Exception e) {
        bitmap = null;
    } finally {
        fmmr.release();
    }
    return bitmap;
}

最后是创建和使用过滤器的代码:

String[] filters = new String[] {"colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131",  "curves=vintage", "curves=negative", "hue=s=0"};
String[] filterNames = new String[] {"Sepia",  "Vintage", "Negative", "Black/White"};
int loopCounter;

public void setThumbNailImage(Bitmap image) {
    loopCounter = -1;
    mGallery.setVisibility(View.VISIBLE);
    LayoutInflater mInflater = LayoutInflater.from(getActivity());

    ffmpeg = FFmpeg.getInstance(context);

    createNewFileForImageAndVideoNoFilter();
    bitmapToFile(image);

    addFilter(mInflater);

}

private void addFilter(LayoutInflater mInflater){
    loopCounter++;
    View view = mInflater.inflate(R.layout.filter_item,
            mGallery, false);

    createNewFileForFilteredImage();



    String[] cmd = { "-i",  imageToBeFiltered.toString(), "-filter_complex", filters[loopCounter], imageWithFilter.toString()};

    ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
        @Override
        public void onSuccess(String message) {
            super.onSuccess(message);

            Bitmap image = BitmapFactory.decodeFile(imageWithFilter.getAbsolutePath());
            ImageView img = (ImageView) view.findViewById(R.id.filter_item_image);
            img.setImageBitmap(image);
            mGallery.addView(view);
            TextView txt = (TextView) view.findViewById(R.id.filter_item_name);
            txt.setText(filterNames[loopCounter]);
            view.setId(loopCounter);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    filteredVideo.delete();
                    String[] cmd = { "-i",  originalVideoFile.toString(), "-filter_complex", filters[view.getId()], "-pix_fmt", "yuv420p",  filteredVideo.toString()};
                    ffmpeg.execute(cmd, new ExecuteBinaryResponseHandler() {
                        @Override
                        public void onSuccess(String message) {
                            super.onSuccess(message);
                            System.out.println("ffmpegVideo: succ" + message);
                            Toast.makeText(context, "Done with adding flter", Toast.LENGTH_LONG).show();
                            somethingYouWannaDoWithTheOutputFile();
                        }
                        @Override
                        public void onFailure(String message) {
                            super.onFailure(message);
                            System.out.println("ffmpegVideo: faill" + message);
                        }

                        @Override
                        public void onProgress(String message) {
                            super.onProgress(message);
                            Toast.makeText(context, "Adding filter", Toast.LENGTH_LONG).show();
                        }
                    });

                }
            });

            if (loopCounter+1 < filters.length) addFilter(mInflater);
        }
        @Override
        public void onFailure(String message) {
            super.onFailure(message);
            if (loopCounter+1 < filters.length) addFilter(mInflater);
        }
    });
}


public void createNewFileForImageAndVideoNoFilter(){
    filteredVideo = new File(context.getFilesDir()+ Common.TEMP_LOCAL_DIR + "/" + "filteredVideo.mp4");
    imageToBeFiltered = new File(context.getFilesDir()+ Common.TEMP_LOCAL_DIR + "/" + "_imageToBeFiltered.png");
    if(filteredVideo.exists()){
        filteredVideo.delete();
        imageToBeFiltered.delete();
    }
}

private void bitmapToFile(Bitmap bitmap){
    try {
        OutputStream os = new BufferedOutputStream(new FileOutputStream(imageToBeFiltered));
        bitmap.compress(Bitmap.CompressFormat.PNG, 0, os);
        os.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

private void createNewFileForFilteredImage(){
    imageWithFilter = new File(context.getFilesDir()+ Common.TEMP_LOCAL_DIR + "/" + "_filteredImage.png");
    if(imageWithFilter.exists()){
        imageWithFilter.delete();
    }
}

起初我被损坏了.mp4,因为我没有添加"-pix_fmt", "yuv420p"。你可以在这里阅读更多信息:FFmpeg video filters corrupt mp4 file

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 1970-01-01
    • 2020-07-10
    相关资源
    最近更新 更多