В данной статье описывается возможность создания превью видео файла на сервере и дальнейшее отображение в Android.
Получение превью
Видео можно взять из камеры android, но здесь будет показан пример когда файл уже есть на сервере и его нужно обработать.
Допустим мы получили некий файл video.mp4
Для дальнейшей работы с видео нам потребуется ffmpeg. Переходим по ссылке и скачиваем требуемый дистрибутив.
Примечание: Манипуляции с ffmpeg будут осуществляться в операционной системе Windows 10.
Далее нам нужно сделать так чтобы команда ffmpeg была доступна из командной строки. Для этого нужно каталог с бинарными файлами добавить в переменную среду.




Далее нам нужно с ним провести следующие манипуляции:
- узнать размер кадра
 
Для этого нам понадобиться команда ffprobe — она позволяет узнать информацию о видео файле. На требуется в этой информации найти видео поток.

Из полученной информации мы понимаем, размер кадра у видео равен
width=1280 height=720
- количество фрагментов
 
По аналогии с определение размера кадра можно узнать и количество фрагментов. Данная информация храниться в параметре nb_frames и она равна 739

- выполнить процедуру преобразования
 
Для запуска преобразования видео в изображение нам нужно выполнить следующую команду:
ffmpeg -loglevel panic -y -i "video.mp4" -frames 1 -q:v 1 -vf "select=not(mod(n\,7)),scale=-1:120,tile=100x1" video_preview.jpg
, где:
- loglevel panic — вывод логов, отображается только основная информация
 - «video.mp4» — путь к входному файлу
 - frames 1 — требуется достать только один фрагмент за одну выборку
 - q:v — качество выходных данных, 0 — наилучшее качество
 - vf select — выборка кадров
- not(mod(n\,7)) — получаем каждый 7 кадр
 - scale=-1:120 — указываем что высота выбранного кадра должна быть 120 пикселей
 - title=100×1 — количество фрагментов в результат, тут 100
 
 - video_preview.jpg — результат обработки
 
Примечание: Откуда числа 7 и 100? Все просто, 100 — это число которое мы сами решаем указать, сколько кадров мы хотим видеть в результате, а вот 7 вычисляется по следующей формуле
nb_frames / 100 т.е. 739 / 100 = ~7
В результате выполнения должен сформироваться файл в котором будет множество фрагментов:

Далее указанный файл нам нужно вывести в Android.
Вывод превью от ffmpeg в Android
Исходный код программы содержится тут
git clone git://git.appcode.pw/ffmpeg-video-preview-android.git
Основные моменты:
- созданное превью помещается в папку res/raw
 

- activity_main.xml содержит следующий код
 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:gravity="center">
    <ImageView
        android:id="@+id/ivPreview"
        android:layout_width="213dp"
        android:layout_height="120dp" />
</LinearLayout>
Тут в файле один контейнер в котором есть ImageView
Примечание: размеры контейнера получаются следующим образом: высота берется из файла video_preview.jpg, вот ширина вычисляется по следующей формуле:
(video width * preview height) / video height Результатом будет ~213
- MainActivity содержит следующий код:
 
String TAG = "LOG";
int width = 213;
int height = 120;
int maxWidth = 0;
int x = 0;
InputStream inputStream = null;
ImageView ivPreview = null;
Bitmap bmp = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    inputStream = getResources().openRawResource(R.raw.video_preview);
    bmp = BitmapFactory.decodeStream(inputStream);
    maxWidth = bmp.getWidth();
    ivPreview = findViewById(R.id.ivPreview);
    Timer timer = new Timer();
    timer.schedule(new UpdateTimeTask(), 0, 41);
    Log.d(TAG, "main thread: " + Thread.currentThread().getId());
}
class UpdateTimeTask extends TimerTask {
    public void run() {
        Log.d(TAG, "timer thread: " + Thread.currentThread().getId());
        try {
            final Bitmap resizedbitmap = Bitmap.createBitmap(bmp, x, 0, width, height);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    ivPreview.setImageBitmap(resizedbitmap);
                }
            });
            x += width;
            if (x >= maxWidth) {
                x = 0;
            }
        }catch (IllegalArgumentException e){
            Log.d(TAG, "ошибка");
        }
    }
}
Основные моменты здесь следующие:
- наше превью нужно преобразовать в Bitmap
 
inputStream=getResources().openRawResource(R.raw.video_preview); Bitmap bmp = BitmapFactory.decodeStream(inputStream);
- узнать длину изображения
 
maxWidth = bmp.getWidth(); // это нам нужно для определения конца кадров
- создаем свой таймер, который должен выводить в нашем ImageView Bitmap
 
Примечание: интервал времени можно выбрать любой. Я выбирал из условия 24 кадра в секунду.
- в обработке таймера просто вырезаем требуемое изображение из оригинального Bitmap
 
final Bitmap resizedbitmap = Bitmap.createBitmap(bmp, x, 0, width, height);
runOnUiThread(new Runnable() {
    @Override
    public void run() {
        ivPreview.setImageBitmap(resizedbitmap);
    }
});
- и сохраняем позицию x с которого нужно получить следующий кадр. И так делаем до тех пор пока не достигнем максимальной длины, после чего просто сбрасываем текущее положение на 0.
 
x += width;
if (x >= maxWidth) {
    x = 0;
}