我正在编写一个程序来加速视频的安静部分,并且我希望支持长达2个小时的视频。
这是基于命令行的程序。我正在XCode中构建它,然后将已编译的程序复制到带有输入视频的文件夹中,然后从终端运行它。
我基本上是根据ffmpeg的silence_detect功能的时间生成一个命令来运行一个非常大的复杂过滤器,以加快视频的其他“部分”的速度,然后将所有这些部分连接在一起。
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include "CoreFoundation/CoreFoundation.h"
using namespace std;
int main(int argc, const char * argv[]) {
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
char path[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
{
// error!
}
CFRelease(resourcesURL);
/************************************/
/***********Getting Input************/
/************************************/
chdir(path);
std::cout << "Current Path: " << path << std::endl;
for (int i = 0; i < argc; i++){
printf("argv[%d] = %s\n", i, argv[i]);
}
string inpath = "input.mp4";
string outpath = "output.mp4";
if(argc >= 1){
inpath = argv[1];
}
if(argc >= 2){
outpath = argv[2];
}
string volcall = "ffmpeg -i \"" + inpath + "\" -af silencedetect=noise=-30dB:d=0.5 -f null - 2> " + inpath + "vol.txt";
system(volcall.c_str());
/************************************/
/***********File Analysis************/
/************************************/
cout<<"Starting File Analysis"<<endl;
string s;
string sTotal;
string sNew;
ifstream in;
in.open(inpath + "vol.txt");
//loads entire document into sTotal
while(!in.eof()) {
getline(in, s);
sTotal += s + "\n";
}
size_t pos = sTotal.find("silence_start"); //find location of first time
sNew = sTotal.erase(0,pos); //delete everything prior to location found
//START TIME EXTRACTION
vector<double> startArr;
vector<double> endArr;
string term = "silence_start";
int bpos = 0;
while ((bpos = sNew.find(term,bpos)) != -1)
{
int posStart = 15 + bpos;
string timeStart = sNew.substr (posStart,7);
float timeSrt = stof (timeStart);
startArr.push_back(timeSrt);
cout<< (timeSrt / 2) <<endl;
bpos += term.length();
}
//END TIME EXTRACTION
string term2 = "silence_end";
int bpos2 = 0;
while ((bpos2 = sNew.find(term2,bpos2)) != -1)
{
int posStart = 13 + bpos2;
string timeEnd = sNew.substr (posStart,7);
float timeNd = stof (timeEnd);
endArr.push_back(timeNd);
cout<< (timeNd / 2) <<endl;
bpos2 += term.length();
}
vector<double> totalArr(startArr);
totalArr.insert( totalArr.end(), endArr.begin(), endArr.end() );
sort(totalArr.begin(), totalArr.end());
in.close();
/************************************/
/***********Video Editing************/
/************************************/
cout<<"Starting Video Editing"<<endl;
string cmd = "";
string acmd = "";
cmd+= "ffmpeg -i " + inpath + " -filter_complex \"";
double first_speed = 1.0;
double second_speed = 2.0;
vector<double> times(totalArr); //starts with next timecode after 0, ends with last timecode
int numTimes = times.size();
cmd= cmd + "[0:v]trim=0:" + to_string(times[0]) + ",setpts=" + to_string(first_speed) + "*(PTS-STARTPTS)[v0]; ";
acmd= acmd + "[0:a]atrim=0:" + to_string(times[0]) + ",asetpts=PTS-STARTPTS,atempo=" + to_string(first_speed) + "[a0]; ";
double mySpeed;
int i;
for(i = 0; i < numTimes - 1; i++){
mySpeed = i%2==1? first_speed : second_speed;
cmd= cmd + "[0:v]trim=" + to_string(times[0 + i]) + ":" + to_string(times[1 + i]) + ",setpts=" + to_string(1 / mySpeed) + "*(PTS-STARTPTS)[v" + to_string(i+1) + "]; ";
acmd= acmd + "[0:a]atrim=" + to_string(times[0 + i]) + ":" + to_string(times[1 + i]) + ",asetpts=PTS-STARTPTS,atempo=" + to_string(mySpeed) + "[a" + to_string(i+1) + "]; ";
}
cmd = cmd + "[0:v]trim=" + to_string(times[i]) + ",setpts=" + to_string(1/(i%2==1? first_speed : second_speed)) + "*(PTS-STARTPTS)[v" + to_string(i + 1) + "]; ";
acmd= acmd + "[0:a]atrim=" + to_string(times[i]) + ",asetpts=PTS-STARTPTS,atempo=" + to_string(i%2==1? first_speed : second_speed) + "[a" + to_string(i + 1) + "]; ";
string cnc = "";
for(int j = 0; j < i + 2; j++){
cnc = cnc + "[v" + to_string(j) + "][a" + to_string(j) + "]";
}
cnc = cnc + "concat=n=" + to_string(i + 2) + ":v=1:a=1";
cmd = cmd + acmd + cnc + "\" -preset superfast -profile:v baseline " + outpath;
system(cmd.c_str());
return 0;
}
我希望输出的视频长度比输入的短。 (如果输入的视频没有安静的部分,则长度相等)。
这有时效果很好:
这是在shortening Jacksfilms' 'woooooww' video from 17.200 seconds to 13.434 seconds.中工作的实际命令
ffmpeg -loglevel verbose -i WOOOW.mp4 -filter_complex "[0:v]trim=0:0.978250,setpts=1.000000*(PTS-STARTPTS)[v0]; [0:v]trim=0.978250:2.452020,setpts=0.500000*(PTS-STARTPTS)[v1]; [0:v]trim=2.452020:3.706520,setpts=1.000000*(PTS-STARTPTS)[v2]; [0:v]trim=3.706520:5.565560,setpts=0.500000*(PTS-STARTPTS)[v3]; [0:v]trim=5.565560:7.122250,setpts=1.000000*(PTS-STARTPTS)[v4]; [0:v]trim=7.122250:8.272020,setpts=0.500000*(PTS-STARTPTS)[v5]; [0:v]trim=8.272020:8.892350,setpts=1.000000*(PTS-STARTPTS)[v6]; [0:v]trim=8.892350:10.034100,setpts=0.500000*(PTS-STARTPTS)[v7]; [0:v]trim=10.034100:11.695400,setpts=1.000000*(PTS-STARTPTS)[v8]; [0:v]trim=11.695400:13.783300,setpts=0.500000*(PTS-STARTPTS)[v9]; [0:v]trim=13.783300,setpts=1.000000*(PTS-STARTPTS)[v10]; [0:a]atrim=0:0.978250,asetpts=PTS-STARTPTS,atempo=1.000000[a0]; [0:a]atrim=0.978250:2.452020,asetpts=PTS-STARTPTS,atempo=2.000000[a1]; [0:a]atrim=2.452020:3.706520,asetpts=PTS-STARTPTS,atempo=1.000000[a2]; [0:a]atrim=3.706520:5.565560,asetpts=PTS-STARTPTS,atempo=2.000000[a3]; [0:a]atrim=5.565560:7.122250,asetpts=PTS-STARTPTS,atempo=1.000000[a4]; [0:a]atrim=7.122250:8.272020,asetpts=PTS-STARTPTS,atempo=2.000000[a5]; [0:a]atrim=8.272020:8.892350,asetpts=PTS-STARTPTS,atempo=1.000000[a6]; [0:a]atrim=8.892350:10.034100,asetpts=PTS-STARTPTS,atempo=2.000000[a7]; [0:a]atrim=10.034100:11.695400,asetpts=PTS-STARTPTS,atempo=1.000000[a8]; [0:a]atrim=11.695400:13.783300,asetpts=PTS-STARTPTS,atempo=2.000000[a9]; [0:a]atrim=13.783300,asetpts=PTS-STARTPTS,atempo=1.000000[a10]; [v0][a0][v1][a1][v2][a2][v3][a3][v4][a4][v5][a5][v6][a6][v7][a7][v8][a8][v9][a9][v10][a10]concat=n=11:v=1:a=1" -preset superfast -profile:v baseline shortWOWOUT.mp4 2> shortWOWOUT.mp4_log.txt
但是有时代码会停止并返回错误:
Assertion start_sample < end_sample || (start_sample == end_sample && !frame->nb_samples) failed at libavfilter/trim.c:303
这似乎仅在ffmpeg渲染3分钟左右的某个位置时发生。似乎与文件大小,分辨率,比特率,帧率或生成的命令的长度没有关联。似乎与输入视频的长度有关,但是我不确定这是什么。一个3分56秒的视频效果不错,但一个5分57英寸的视频却出错了。
是否可以解决此问题?还是当输入视频经过一些未知的截止时间时该程序注定要失败?