FFmpeg-问题缩放和覆盖图像

时间:2019-07-15 05:39:22

标签: android ffmpeg

首先,我正在使用的设备的屏幕尺寸为1080 x 2280 pixels, 19:9 ratio,这一点很重要,稍后将在问题中进行解释。


几个月前,我问了this个问题。提供的答案非常有效:

"-i", video.mp4, "-i", image.png, "-filter_complex", "[0:v]pad=iw: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", outFPS, output.mp4

实施并发布此代码后不久,我开始收到来自用户的消息,抱怨放置在视频顶部的图像在保存后不在同一位置。
我在命令中注意到触摸板的比率上方设置为16:9的比率,换句话说,以上内容不适用于屏幕比率为19:9的设备。

然后我又问了question这个问题,与@Gyan进行了长时间的交谈之后,命令更改为以下内容:

"-i", video.mp4, "-i", image.png, "-filter_complex", "[0:v]scale=iw*sar:ih,setsar=1,pad='max(iw\,2*trunc(ih*9/16/2))':'max(ih\,2*trunc(ow*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", outFPS, output.mp4

在具有16:9比率的设备上进行测试是完美的。


现在使用上述设备进行测试,我将命令中的比率替换为以下内容(19/9/29/19/2):

"-i", video.mp4, "-i", image.png, "-filter_complex", "[0:v]scale=iw*sar:ih,setsar=1,pad='max(iw\,2*trunc(ih*9/19/2))':'max(ih\,2*trunc(ow*19/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", outFPS, output.mp4

这是我得到的结果:

我将播放器的背景更改为绿色,以便于查看。蓝线是我要覆盖的图像

原始视频

original

处理后

after

以下是上述问题。

  • 在原始视频上绘制的线条没有缩放,但仍处于正确的位置。
  • 视频不再是原始大小,宽度和高度减小了,现在可以在视频的左右看到我的播放器背景。

这是我想要达到的结果:

correct

您会注意到以下内容:

  • 视频未调整大小,但仍具有与原始视频相同的尺寸。
  • 绘制的线条仍在同一位置,并且没有缩放
  • 在视频的顶部和底部添加了黑色填充,以填充剩余的空间。绿色背景不再可见。

任何实现上述目标的建议将不胜感激。

我将向用户提供300积分,可以帮助我解决此问题。


编辑1

Here是输入视频,图像和注释部分中要求的预期输出。此设备使用的纵横比为16:9,屏幕尺寸为1920x1080

Here是预期输出的另一个示例(我还包括输入图像和输入视频)。


编辑2

我认为值得一提的是,输入图像将始终是设备屏幕的尺寸/尺寸,因此它也将始终具有与屏幕相同的纵横比。输入视频的大小/尺寸会有所不同。

1 个答案:

答案 0 :(得分:0)

首先,我要感谢@Gyan在此问题上的所有帮助。


该问题是由于我没有为具有缺口显示的设备进行设计/规划而引起的。

在我的应用程序中,我隐藏了状态栏,并且在具有缺口显示(并且用户已将其禁用)的设备上,状态栏应位于顶部的黑色栏上。

如果您查看问题Original video中的图片,您会看到顶部有一个黑条。

我为获得屏幕高度所做的事情如下:

DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
disp.getRealMetrics(displayMetrics);

mWidth = disp.getWidth();
mHeight = disp.getHeight();

我认为这可以解决问题,但是问题是,即使隐藏状态栏,在缺口设备上,屏幕尺寸也会是(实际屏幕高度-状态栏)。

换句话说,我将错误的宽高比传递给FFmpeg。


我要做的就是修复它,我添加了一个视图并将其宽度和高度设置为match_parent。通过这样做,我知道它将始终充满整个屏幕。然后,我使用该视图确定设备的长宽比。


这就是我获得设备的纵横比(视图设置为match_parent)的方式:

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) {
    //public int's
    imageAndVideoAspectForScaling = a+"/"+b+"/"+2;
    imageAndVideoAspectForScalingb = b+"/"+a+"/"+2;
}

然后我检查设备是纵向还是横向,并进行相应的调整:

肖像:

"[0:v]scale=iw*sar:ih,setsar=1,pad='max(iw\\,2*trunc(ih*"+imageAndVideoAspectForScalingb+"))':'max(ih\\,2*trunc(ow*"+imageAndVideoAspectForScaling+"))':(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]"

风景:

"[0:v]scale=iw*sar:ih,setsar=1,pad='max(iw\\,2*trunc(ih*"+imageAndVideoAspectForScaling+"))':'max(ih\\,2*trunc(ow*"+imageAndVideoAspectForScalingb+"))':(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]"