Мне понадобилось время, но я понял это, используя 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 видеофильтры поврежденный файл mp4