Вы упомянули, что видео размером 7 МБ занимает от 30 до 60 секунд.
При выборе скорости и качества всегда есть компромисс.
Я тестировал на своем телефоне, используя файл размером 7 МБ, и это заняло 13 секунд, все еще медленно, но мы не можем ожидать намного лучшего, чем это.
Способы увеличения скорости:
- Понижение частоты кадров с помощью команды
-r
- Изменение битрейта с помощью команд
-b:v
и -b:a
- Измените коэффициент постоянной скорости, используя
-crf
. Значение по умолчанию 21
Диапазон шкалы квантования составляет 0-51: , где 0 - без потерь, 23 - по умолчанию, а 51 - наихудший из возможных. Значение ниже является более высоким качеством , а субъективно вменяемый диапазон составляет 18-28. Считайте, что 18 визуально без потерь или почти так: он должен выглядеть так же или почти так же, как вход, но технически он не без потерь.
Это то, что я нашел, работает лучше всего на большинстве устройств Android:
String[] s = {"-i", VideoPath, "-i", ImagePath, "-filter_complex", "[0:v]pad=iw:if(lte(ih\\,iw)\\,ih\\,2*trunc(iw*16/9/2)):(ow-iw)/2:(oh-ih)/2[v0];[1:v][v0]scale2ref[v1][v0];[v0][v1]overlay=x=(W-w)/2:y=(H-h)/2[v]", "-map", "[v]", "-map", "0:a", "-g", "2", "-c:v", "libx264", "-preset", "ultrafast", "-r", myFrameRate, directoryToStore[0] + "/" + SavedVideoName};
Я немного уменьшил частоту смены кадров, вы можете поэкспериментировать, что вам больше подходит. Я использую Google mp4parser
для получения частоты кадров.
Я должен отдать должное @Gyan, который предоставил мне способ идеально масштабировать изображения, помещаемые поверх видео, вы можете посмотреть на вопрос, который я задал здесь .
Также вы можете удалить команду -g
, которую я использовал выше, для изменения GOP.
Вот ваша команда отредактирована:
String[] cmd = {"-i", videoPath, "-i", waterMark.toString(), "-filter_complex", "[0:v]pad=iw:if(lte(ih\\,iw)\\,ih\\,2*trunc(iw*16/9/2)):(ow-iw)/2:(oh-ih)/2[v0];[1:v][v0]scale2ref[v1][v0];[v0][v1]overlay=x=(W-w)/2:y=(H-h)/2[v]", "-map", "[v]", "-map", "0:a", "-c:v", "libx264", "-preset", "ultrafast", "-r", myFrameRate, outputPath};
Если вы не уверены в частоте кадров, вы можете удалить ее из команды и сначала проверить, не снижена ли ваша скорость.
Попробуйте, если у вас есть какие-либо вопросы, пожалуйста, задавайте.
OP решил пойти со следующей командой:
String[] cmd = {"-y","-i", videoPath, "-i", waterMark.toString(), "-filter_complex", "overlay=(main_w-overlay_w-10):5", "-map", "0:a","-c:v", "libx264", "-crf", "28","-preset", "ultrafast" ,outputPath};
Редактировать
Просто добавьте к упомянутой мной команде и предоставьте подробное объяснение того, как ее использовать и т. Д .:
String[] cmd = {"-i", videoPath, "-i", waterMark.toString(), "-filter_complex", "[0:v]pad=iw:if(lte(ih\\,iw)\\,ih\\,2*trunc(iw*16/9/2)):(ow-iw)/2:(oh-ih)/2[v0];[1:v][v0]scale2ref[v1][v0];[v0][v1]overlay=x=(W-w)/2:y=(H-h)/2[v]", "-map", "[v]", "-map", "0:a", "-c:v", "libx264", "-preset", "ultrafast", "-r", myFrameRate, outputPath};
Это для устройств с соотношением сторон дисплея 16:9
. Если вы хотите, чтобы этот фильтр работал на всех устройствах, вам нужно получить соотношение сторон устройства и изменить фильтр 16/9/2
соответственно.
Вы можете получить соотношение сторон устройства, создав следующие методы:
int gcd(int p, int q) {
if (q == 0) return p;
else return gcd(q, p % q);
}
void ratio(int a, int b) {
final int gcd = gcd(a,b);
if(a > b) {
setAspectRatio(a/gcd, b/gcd);
} else {
setAspectRatio(b/gcd, a/gcd);
}
}
void setAspectRatio(int a, int b) {
System.out.println("aspect ratio = "+a + " " + b);
//This is the string that will be used in the filter (instead of hardcoding 16/9/2
filterAspectRatio = a + "/" + b + "/" + "2";
}
Теперь у вас есть правильное соотношение сторон, и вы можете соответственно изменить фильтр.
Затем создайте водяной знак и добавьте его в вид, сделайте для этого вида размер устройства (match_parent
) и масштабируйте / разместите водяной знак там, где вы хотите, чтобы он был. Затем вы можете получить растровое изображение, вызвав:
Bitmap waterMarkBitmap = watermarkView.getDrawingCache();
и создайте файл из Bitmap
, например:
String outputFilename = "myCoolWatermark.png"; //provide a name for you saved watermark
File path = Environment.getExternalStorageDirectory(); //this can be changed to where you want to store the bitmap
File waterMark = new File(path, outputFilename);
try (FileOutputStream out = new FileOutputStream(waterMark)) {
waterMarkBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // PNG is a lossless format, the compression factor (100) is ignored
} catch (IOException e) {
e.printStackTrace();
}
Водяной знак создан и может быть использован повторно, или вы можете удалить его, когда закончите с ним.
Теперь вы можете вызвать указанную выше команду.