我在我的应用程序中使用FFmpeg从视频中提取帧,这些帧将被添加到修剪视频视图中,您可以在视频中的特定时间看到视频中发生的事情。因此每个帧需要代表视频中的一些时间。
我不太明白FFmpeg是如何制作帧的。这是我的代码:
"-i",
videoCroppedFile.getAbsolutePath(),
"-vf",
"fps=1/" + frameSeperation,
mediaStorageDir.getAbsolutePath() +
"/%d.jpg"
我的应用程序允许您录制最长20秒的视频。从视频中提取的帧数取决于捕获的视频的持续时间。使用以下代码计算frameSeperation。
String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long videoLength = Long.parseLong(time) / 1000;
double frameSeperationDouble = (double) videoLength;
// Divide by 11 because there is a maximum of 11 frames on trim video view
frameSeperationDouble /= 11;
frameSeperationDouble = Math.ceil(frameSeperationDouble);
int frameSeperation = (int) frameSeperationDouble;
也许上述逻辑非常糟糕,如果有更好的方法请有人告诉我。
无论如何我运行代码,下面是一些测试用例:
没有一致性,因此我发现很难在每个帧上加上时间戳。我觉得我的逻辑是错误的,或者我不理解。非常感谢任何帮助
更新1
所以我做了你在评论中所说的话:
final FFmpeg ffmpeg = FFmpeg.getInstance(mContext);
final File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ mContext.getPackageName()
+ "/vFrames");
if (!mediaStorageDir.exists()){
mediaStorageDir.mkdirs();
}
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(mContext, Uri.fromFile(videoCroppedFile));
String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long videoLength = Long.parseLong(time) / 1000;
double frameSeperationDouble = (double) videoLength / 8;
retriever.release();
final String cmd[] = {
"-i",
videoCroppedFile.getAbsolutePath(),
"-vf",
"fps=1/" + frameSeperationDouble,
"-vframes," + 8,
mediaStorageDir.getAbsolutePath() +
"/%d.jpg"
};
我也尝试了"-vframes=" + 8
我将vFrame放入cmd的同一点。现在似乎没有工作,现在没有从视频中提取帧
答案 0 :(得分:0)
这是fps=x
的有效流程,使用默认的舍入方法near
,
生成1/x
秒的间隔,例如。对于x=1/3
,间隔为0-3s,3-6s,6-9s ......在每个间隔内,选择一个时间戳最接近该间隔中点的早期帧。当最近的帧属于较早的间隔时,这可能导致重复的帧,并且已经为该间隔选择了帧。如果source是可变帧率,可能会发生。
在您的情况下,如果可能,我建议避免舍入或剥离小数值。或者最后做。