胡斌

part of pip,not finished

... ... @@ -5,6 +5,8 @@ VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "merge_av", "merge_av\merge_av.vcxproj", "{F607DD90-3E62-40BA-BF8A-185E597D646D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pip", "pip\pip.vcxproj", "{7D6B14AD-7FD2-45F1-A196-A2455406D4FB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
... ... @@ -15,6 +17,10 @@ Global
{F607DD90-3E62-40BA-BF8A-185E597D646D}.Debug|Win32.Build.0 = Debug|Win32
{F607DD90-3E62-40BA-BF8A-185E597D646D}.Release|Win32.ActiveCfg = Release|Win32
{F607DD90-3E62-40BA-BF8A-185E597D646D}.Release|Win32.Build.0 = Release|Win32
{7D6B14AD-7FD2-45F1-A196-A2455406D4FB}.Debug|Win32.ActiveCfg = Debug|Win32
{7D6B14AD-7FD2-45F1-A196-A2455406D4FB}.Debug|Win32.Build.0 = Debug|Win32
{7D6B14AD-7FD2-45F1-A196-A2455406D4FB}.Release|Win32.ActiveCfg = Release|Win32
{7D6B14AD-7FD2-45F1-A196-A2455406D4FB}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
... ...
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <string.h>
#include <list>
#include <deque>
#include "tools.h"
bool only_print = false;
bool keep_tmp_files = false;
using namespace std;
enum media_type{
mt_audio = 0,
mt_video = 1,
mt_av = 3,
};
enum timestamp_type{
tt_start = 0,
tt_end = 1,
};
class fileinfo {
public:
float start_time;
float end_time;
string name;
int index;
media_type m_type;
int channel;
};
class media_info {
public:
float type_time;//the time for start or end according to the m_type
float start_time;
float end_time;
string name;
float duration;
int index;
int channel;
media_type m_type;
timestamp_type t_type;
};
vector<fileinfo> media_files;
void run_shell_cmd(const char * cmd)
{
if (only_print){
printf("%s\n", cmd);
}
else
{
printf("run command:%s\n", cmd);
system(cmd);
}
}
#ifdef WIN32
#include <Windows.h>
char exe_path[MAX_PATH] = { 0 };
int GetExePath()
{
char path_buffer[MAX_PATH] = "";
char drive[32] = "";
char dir[256] = "";
char fname[64] = "";
char ext[32] = "";
GetModuleFileNameA(NULL, path_buffer, 256);
_splitpath(path_buffer, drive, dir, fname, ext);
strcpy(exe_path, drive);
strcat(exe_path, dir);
return 0;
}
#endif
char cfg_path[1024];
void get_config_path(){
#ifdef WIN32
GetExePath();
strcpy(cfg_path, exe_path);
#else
strcpy(cfg_path, getenv("HOME"));
strcat(cfg_path, "/merge_av/");
#endif
}
const char * default_vcodec_param = "-vcodec libx264 -level 3.1 -preset veryfast -g 100 -r 20 -bf 0 -vsync cfr";
const char * default_acodec_param = "-acodec copy";
const char * default_av_codec_param = "-acodec aac -vcodec libx264 -level 3.1 -preset veryfast -g 100 -r 20 -bf 0 -vsync cfr";
const char * default_pip_param = "-filter_complex \"[1:v]scale = w = 80:h = 60 : force_original_aspect_ratio = decrease[b]; [0:v][b]overlay = x = 0:y = 0\" -filter_complex amix=inputs=2:duration=first:dropout_transition=2,volume=1";
char av_codec_param[1024];
char vcodec_param[1024];
char acodec_param[1024];
char pip_param[1024];
bool first_time_set = false;
float start_time = 0.0f;
void addinfo(string t, string name, bool bstart){
media_type mtype = name.substr(name.length() - 4, name.length()) == ".aac" ? mt_audio : mt_video;
if (bstart) {
fileinfo f;
f.start_time = atof(t.c_str());
f.end_time = f.start_time;
f.name = name;
f.m_type = mtype;
if (!first_time_set) {
first_time_set = true;
start_time = f.start_time;
}
f.start_time -= start_time;
media_files.push_back(f);
}
else {
int i;
for (i = 0; i < media_files.size(); i++) {
if (media_files[i].name == name) {
media_files[i].end_time = atof(t.c_str());
media_files[i].end_time -= start_time;
break;
}
}
if (i == media_files.size())
{
printf("\nerror ,file : %s close but not started!", name.c_str());
}
}
}
void addinfo(float start, float duration, string name, int channel){
media_type mtype = mt_av;
fileinfo f;
f.start_time = start;
f.end_time = f.start_time + duration;
f.name = name;
f.m_type = mtype;
f.channel = channel;
media_files.push_back(f);
}
void split(string str, string separator, vector<string> &result, bool includeEmptyItem = false) {
result.clear();
string::size_type position = str.find(separator);
string::size_type lastPosition = 0;
int separatorLength = separator.length();
while (position != str.npos) {
string s = str.substr(lastPosition, position - lastPosition);
if (!s.empty() || includeEmptyItem)
result.push_back(s);
lastPosition = position + separatorLength;
position = str.find(separator, lastPosition);
}
result.push_back(str.substr(lastPosition, string::npos));
}
void split_audio(const char * audiofile, float audio_start, float duration, char * destfile)
{
char buf[2048];
sprintf(buf, "ffmpeg -y -i %s -ss %.3f -t %.3f %s %s", audiofile, audio_start, duration, acodec_param, destfile);
run_shell_cmd(buf);
}
void split_av(const char * mediafile, float start, float duration, char * destfile)
{
char buf[2048];
sprintf(buf, "ffmpeg -y -i %s -ss %.3f -t %.3f %s %s", mediafile, start, duration, av_codec_param, destfile);
run_shell_cmd(buf);
}
void get_video_first_frame_jpeg(const char * video, const char * destfile)
{
char buf[2048];
sprintf(buf, "ffmpeg -y -i %s -vframes 1 -ss 0 -f mjpeg -an %s", video, destfile);
run_shell_cmd(buf);
}
void merge_audio_pic(const char * audio, const char * picfile, const char * destfile)
{
char buf[2048];
sprintf(buf, "ffmpeg -y -loop 1 -i %s -i %s -loop 0 -shortest %s %s %s", picfile, audio, acodec_param, vcodec_param, destfile);
run_shell_cmd(buf);
}
void merge_audio_video(const char * audio, const char * video, const char * destfile)
{
char buf[2048];
sprintf(buf, "ffmpeg -y -i %s -i %s %s %s %s", audio, video, acodec_param, vcodec_param, destfile);
run_shell_cmd(buf);
}
void merge_video_pip(const char * ch0, const char * ch1, const char * destfile)
{
char buf[2048];
sprintf(buf, "ffmpeg -i %s -i %s %s %s %s", ch0, ch1, pip_param, av_codec_param, destfile);
run_shell_cmd(buf);
}
void merge_video_silence(fileinfo video, const char * aacfile, const char * destfile)
{
char buf[2048];
sprintf(buf, "ffmpeg -y -i %s -i %s -shortest %s %s %s", aacfile, video.name.c_str(), acodec_param, vcodec_param, destfile);
run_shell_cmd(buf);
}
void concate_files(vector<string > merged_files, const char * destfile)
{
char buf[2048];
#ifdef WIN32
sprintf(buf, "copy /B %s ", merged_files[0].c_str());
for (int i = 1; i < merged_files.size(); i++) {
strcat(buf, " + /B ");
strcat(buf, merged_files[i].c_str());
}
strcat(buf, " ");
#else
strcpy(buf, "cat ");
for (int i = 0; i < merged_files.size(); i++) {
strcat(buf, " ");
strcat(buf, merged_files[i].c_str());
}
strcat(buf, "> ");
#endif // WIN32
strcat(buf, destfile);
run_shell_cmd(buf);
}
void adjust_dest_timecode(const char * src, const char * dest)
{
char buf[2048];
sprintf(buf, "ffmpeg -y -i %s -acodec copy -vcodec copy %s", src, dest);
run_shell_cmd(buf);
}
#ifndef WIN32
#include <unistd.h>
#endif
void remove_file(const char * file)
{
#ifdef WIN32
_unlink(file);
#else
unlink(file);
#endif
}
void removefiles(vector<string> files)
{
for (int i = 0; i < files.size(); i++) {
remove_file(files[i].c_str());
}
}
float parse_ffmpeg_duration(const char * file)
{
FILE * fp = fopen(file, "rb");
if (!fp) {
printf("\nOpen %s error\n", file);
return -1.0;
}
fseek(fp, 0l, SEEK_END);
long file_len = ftell(fp);
fseek(fp, 0l, SEEK_SET);
char * content = new char[file_len + 1];
fread(content, 1, file_len, fp);
fclose(fp);
content[file_len] = 0;
if (!keep_tmp_files) {
remove_file(file);
}
char * pDuration = strstr(content, "Duration:");
if (!pDuration){
printf("\ncan't find 'Duration:' in %s\n", file);
delete content;
return -1.0;
}
char * pComma = strstr(pDuration, ",");
if (!pDuration){
printf("\ncan't find ',' after 'Duration:' in %s\n", file);
delete content;
return -1.0;
}
int len = pComma - pDuration - 10;
strncpy(content, pDuration + 10, len);
content[len] = 0;
vector <string > hms;
split(content, ":", hms);
delete content;
if (hms.size() != 3) {
printf("\nerro parsing duration in %s, the duration string is:%s\n", file, content);
delete content;
return -1.0;
}
int hour = atoi(hms[0].c_str());
int minute = atoi(hms[1].c_str());
float sec = atof(hms[2].c_str());
return hour * 3600 + minute * 60 + sec;
}
float get_file_duration(const char *mediafile, bool bVideo)
{
char buf[2048];
if (bVideo){
sprintf(buf, "ffmpeg -y -i %s -vcodec copy -an %s.mkv", mediafile, mediafile);
}
else {
sprintf(buf, "ffmpeg -y -i %s -acodec copy -vn %s.mkv", mediafile, mediafile);
}
run_shell_cmd(buf);
#ifdef WIN32
sprintf(buf, "ffmpeg -i %s.mkv > %s.txt 2>&1", mediafile, mediafile);
#else
sprintf(buf, "ffmpeg -i %s.mkv &> %s.txt", mediafile, mediafile);
#endif
run_shell_cmd(buf);
if (!keep_tmp_files) {
char buf[2048];
sprintf(buf, "%s.mkv", mediafile);
remove_file(buf);
}
sprintf(buf, "%s.txt", mediafile);
return parse_ffmpeg_duration(buf);
}
void get_duration_from_video_file()
{
bool tmp = only_print;
only_print = false;
for (int i = 0; i < media_files.size(); i++){
if (media_files[i].m_type == mt_video) {
float duration = get_file_duration(media_files[i].name.c_str(), true);
if (duration >= 0.1) {
printf("file:%s , duration in recording file: %.3f, duration parsed from file: %.3f\n", media_files[i].name.c_str(), media_files[i].end_time - media_files[i].start_time, duration);
media_files[i].end_time = media_files[i].start_time + duration;
}
}
}
only_print = tmp;
}
int merge_audio_file(vector<string> & files, const char * dest)
{
char buf[2048],tsfile[1024];
vector<string> tsfiles;
for (int i = 0; i < files.size(); i++){
strcpy(tsfile, files[i].c_str());
strcat(tsfile, ".ts");
tsfiles.push_back(tsfile);
sprintf(buf, "ffmpeg -y -i %s -acodec copy -vn %s", files[i].c_str(), tsfile);
run_shell_cmd(buf);
}
sprintf(tsfile, "m_%s.ts", dest);
concate_files(tsfiles, tsfile);
adjust_dest_timecode(tsfile, dest);
if (!keep_tmp_files){
tsfiles.push_back(tsfile);
removefiles(tsfiles);
}
return 0;
}
list <media_info> sorted_media;
deque<media_info> sorted_infos;
vector<media_info> media_infos;
vector<string > merged_files;
vector<string> tmp_files;
int nv; // the index of processing video file
int nf;//the index of processing target merged ts
char destfile[1024], audio_file[1024], pic_file[1024];
char blank_pic_file[1024];
char silence_aac_file[1024];
char out_info_file[1024];
FILE * fp_out_info = NULL;
void add_media_info(media_info m)
{
list<media_info>::iterator it = sorted_media.begin();
for (; it != sorted_media.end(); it++){
if (it->type_time > m.type_time){
break;
}
}
sorted_media.insert(it, m);
}
void add_media_infos()
{
for (int i = 0; i < media_files.size(); i++) {
fileinfo f = media_files[i];
media_info m;
m.index = i;
m.name = f.name;
m.start_time = f.start_time;
m.end_time = f.end_time;
m.m_type = f.m_type;
m.t_type = tt_start;
m.channel = f.channel;
m.duration = f.end_time - f.start_time;
m.type_time = m.start_time;
add_media_info(m);
m.t_type = tt_end;
m.type_time = m.end_time;
add_media_info(m);
}
list<media_info>::iterator it = sorted_media.begin();
for (int i=0; it != sorted_media.end(); it++, i++ ){
sorted_infos.push_back(*it);
}
}
void unifiy_start_time()
{
float min_start = media_files[0].start_time;
//get the min start
for (int i = 1; i < media_files.size(); i++) {
if (min_start > media_files[i].start_time) {
min_start = media_files[i].start_time;
}
}
//all the file start sub the min start
for (int i = 0; i < media_files.size(); i++) {
media_files[i].start_time -= min_start;
media_files[i].end_time -= min_start;
}
}
void init()
{
strcpy(blank_pic_file, cfg_path);
strcat(blank_pic_file, "blank.jpg");
strcpy(silence_aac_file, cfg_path);
strcat(silence_aac_file, "silence.aac");
unifiy_start_time();
add_media_infos();
nv = 0;
nf = 0;
}
int merge_audio_video(vector<media_info> & files)
{
vector<string> merge_audio_files;
int nsilence = 0;
media_info video = files[0];
float start_time = video.start_time;
for (int i = 1; i < files.size() - 1; i += 2){
media_info audio = files[i];
media_info audio_end = files[i + 1];
if (audio.type_time - start_time > 0.1){
sprintf(audio_file, "%d_%d_silence.aac", nf, nsilence++);//a duration of silence
split_audio(silence_aac_file, 0, audio.type_time - start_time, audio_file);
merge_audio_files.push_back(audio_file);
tmp_files.push_back(audio_file);
}
if (audio.type_time - audio.start_time > 0.10 || audio_end.end_time - audio_end.type_time > 0.10) {
sprintf(audio_file, "%d_%s", nf, audio.name.c_str());
split_audio(audio.name.c_str(), audio.type_time - audio.start_time, audio_end.type_time - audio.type_time, audio_file);
tmp_files.push_back(audio_file);
}
else{
strcpy(audio_file, audio.name.c_str());
}
start_time = audio_end.type_time;
merge_audio_files.push_back(audio_file);
if (i == files.size() - 2){
if (video.end_time - audio_end.type_time > 0.1){
sprintf(audio_file, "%d_%d_silence.aac", nf, nsilence++);//a duration of silence
split_audio(silence_aac_file, 0, video.end_time - audio_end.type_time, audio_file);
merge_audio_files.push_back(audio_file);
tmp_files.push_back(audio_file);
}
}
}
sprintf(audio_file, "%d_merged.aac", nf);
merge_audio_file(merge_audio_files, audio_file);
tmp_files.push_back(audio_file);
sprintf(destfile, "%d.ts", nf);
merge_audio_video(audio_file, video.name.c_str(), destfile);
merged_files.push_back(destfile);
nf++;
return 0;
}
int merge_video_pip(vector<media_info> & files)
{
vector<string> merge_video_files;
int nsilence = 0;
media_info video = files[0];
float start_time = video.start_time;
for (int i = 1; i < files.size() - 1; i += 2){
media_info audio = files[i];
media_info audio_end = files[i + 1];
if (audio.type_time - start_time > 0.1){
sprintf(audio_file, "%d_%d_silence.aac", nf, nsilence++);//a duration of silence
split_audio(silence_aac_file, 0, audio.type_time - start_time, audio_file);
merge_video_files.push_back(audio_file);
tmp_files.push_back(audio_file);
}
if (audio.type_time - audio.start_time > 0.10 || audio_end.end_time - audio_end.type_time > 0.10) {
sprintf(audio_file, "%d_%s", nf, audio.name.c_str());
split_audio(audio.name.c_str(), audio.type_time - audio.start_time, audio_end.type_time - audio.type_time, audio_file);
tmp_files.push_back(audio_file);
}
else{
strcpy(audio_file, audio.name.c_str());
}
start_time = audio_end.type_time;
merge_video_files.push_back(audio_file);
if (i == files.size() - 2){
if (video.end_time - audio_end.type_time > 0.1){
sprintf(audio_file, "%d_%d_silence.aac", nf, nsilence++);//a duration of silence
split_audio(silence_aac_file, 0, video.end_time - audio_end.type_time, audio_file);
merge_video_files.push_back(audio_file);
tmp_files.push_back(audio_file);
}
}
}
sprintf(audio_file, "%d_merged.aac", nf);
merge_audio_file(merge_video_files, audio_file);
tmp_files.push_back(audio_file);
sprintf(destfile, "%d.ts", nf);
merge_audio_video(audio_file, video.name.c_str(), destfile);
merged_files.push_back(destfile);
nf++;
return 0;
}
int transcode_files(vector<media_info> files)
{
char video_file[1024];
media_info video = files[0];
media_info video_end = files[1];
if (video.type_time - video.start_time > 0.10 || video_end.end_time - video_end.type_time > 0.10) {
sprintf(video_file, "%d_%s", nf, video.name.c_str());
split_av(video.name.c_str(), video.type_time - video.start_time, video_end.type_time - video.type_time, video_file);
tmp_files.push_back(video_file);
}
else{
strcpy(video_file, video.name.c_str());
}
merged_files.push_back(video_file);
nf++;
return 0;
}
int find_file_between_the_firstfile()
{
int index = sorted_infos[0].index;
int video_index = -1;
for (int i = 1; i < sorted_infos.size(); i++){
if (sorted_infos[i].index == index)
break;
video_index = i;
}
return video_index;
}
int find_video_end()
{
int index = sorted_infos[0].index;
int video_index = 0;
for (int i = 1; i < sorted_infos.size(); i++){
if (sorted_infos[i].index == index){
video_index = i;
break;
}
}
return video_index;
}
bool is_audio_start(int index)
{
return (sorted_infos[index].m_type == mt_audio && sorted_infos[index].t_type == tt_start);
}
bool is_ch0_start(int index)
{
return (sorted_infos[index].channel == 0 && sorted_infos[index].t_type == tt_start);
}
int split_audio_for_video(int audio_start,vector<media_info> & result)
{
media_info audio = sorted_infos[audio_start];
media_info video = sorted_infos[audio_start + 1];
result.clear();
for (int i = 0; i <= audio_start; i++){
result.push_back(sorted_infos[i]);
}
if (sorted_infos[audio_start + 2].index == sorted_infos[audio_start].index){
if (sorted_infos[audio_start + 2].type_time - sorted_infos[audio_start + 1].type_time < 0.1){//no need to split
result.push_back(sorted_infos[audio_start + 2]);//put the audio end to the result
result.push_back(video);//push the video end to the result
for (int i = 0; i <= audio_start + 2; i++){ //remove the infos including the audio end
sorted_infos.pop_front();
}
return 1;
}
}
audio.t_type = tt_end;
audio.type_time = video.type_time;
result.push_back(audio);
result.push_back(video);
for (int i = 0; i <= audio_start +1; i++){ //remove the infos including the video end
sorted_infos.pop_front();
}
audio.t_type = tt_start;
sorted_infos.push_front(audio);
return 0;
}
int split_ch0_for_ch1(int ch0_start, vector<media_info> & result)
{
media_info ch0 = sorted_infos[ch0_start];
media_info ch1 = sorted_infos[ch0_start + 1];
result.clear();
for (int i = 0; i <= ch0_start; i++){
result.push_back(sorted_infos[i]);
}
if (sorted_infos[ch0_start + 2].index == sorted_infos[ch0_start].index){
if (sorted_infos[ch0_start + 2].type_time - sorted_infos[ch0_start + 1].type_time < 0.1){//no need to split
result.push_back(sorted_infos[ch0_start + 2]);//put the audio end to the result
result.push_back(ch1);//push the video end to the result
for (int i = 0; i <= ch0_start + 2; i++){ //remove the infos including the audio end
sorted_infos.pop_front();
}
return 1;
}
}
ch0.t_type = tt_end;
ch0.type_time = ch1.type_time;
result.push_back(ch0);
result.push_back(ch1);
for (int i = 0; i <= ch0_start + 1; i++){ //remove the infos including the video end
sorted_infos.pop_front();
}
ch0.t_type = tt_start;
sorted_infos.push_front(ch0);
return 0;
}
int split_audio_for_pic(vector<media_info> & result)
{
media_info audio = sorted_infos[0];
media_info video = sorted_infos[1];
result.clear();
for (int i = 0; i < 1; i++){
result.push_back(sorted_infos[i]);
}
if (sorted_infos[2].index == sorted_infos[0].index){
if (sorted_infos[2].type_time - sorted_infos[1].type_time < 0.1){//no need to split
result.push_back(sorted_infos[2]);//put the audio end to the result
for (int i = 0; i < 3; i++){
sorted_infos.pop_front();
}
sorted_infos.push_front(video);
return 1;
}
}
audio.t_type = tt_end;
audio.type_time = video.start_time;
result.push_back(audio);
for (int i = 0; i < 2; i++){
sorted_infos.pop_front();
}
audio.t_type = tt_start;
sorted_infos.push_front(audio);
sorted_infos.push_front(video);
return 0;
}
int split_ch0_for_no_process(vector<media_info> & result)
{
media_info first = sorted_infos[0];
media_info second = sorted_infos[1];
result.clear();
for (int i = 0; i < 1; i++){
result.push_back(sorted_infos[i]);
}
if (sorted_infos[2].index == sorted_infos[0].index){
if (sorted_infos[2].type_time - sorted_infos[1].type_time < 0.1){//no need to split
result.push_back(sorted_infos[2]);//put the audio end to the result
for (int i = 0; i < 3; i++){
sorted_infos.pop_front();
}
sorted_infos.push_front(second);
return 1;
}
}
first.t_type = tt_end;
first.type_time = second.start_time;
result.push_back(first);
for (int i = 0; i < 2; i++){
sorted_infos.pop_front();
}
first.t_type = tt_start;
sorted_infos.push_front(first);
sorted_infos.push_front(second);
return 0;
}
void get_front_info(int index_to, vector<media_info> &cur_processing)
{
cur_processing.clear();
for (int i = 0; i <= index_to; i++){
cur_processing.push_back(sorted_infos[i]);
}
for (int i = 0; i <= index_to; i++){
sorted_infos.pop_front();
}
}
int concate_files_and_adjust_timecode(const char * output_dest_file){
if (merged_files.size() == 1){
printf("\n rename %s to %s", merged_files[0].c_str(), output_dest_file);
rename(merged_files[0].c_str(), output_dest_file);
}
else {
concate_files(merged_files, "m.ts");
tmp_files.push_back("m.ts");
adjust_dest_timecode("m.ts", output_dest_file);
}
if (!keep_tmp_files) {
removefiles(tmp_files);
removefiles(merged_files);
}
merged_files.clear();
tmp_files.clear();
return 0;
}
int get_output_file_name(int i, const char * file_prefix, char * outputfile){
char prefix[128];
const char * p = strstr(file_prefix, ".");
if (p) {
strncpy(prefix, file_prefix, p - file_prefix);
prefix[p - file_prefix] = 0;
}
else {
strcpy(prefix, file_prefix);
}
sprintf(outputfile, "%s.ts", prefix, i);
return 0;
}
bool is_need_output(int nOutPutFile, vector<media_info> & cur_processing, const char * first_file, char * outputfile)
{
if (sorted_infos.size()) {
int lastEnd = cur_processing[cur_processing.size() - 1].type_time;
int nextStart = sorted_infos.front().type_time;
if (nextStart - lastEnd < 0.2) {
return false;
}
}
get_output_file_name(nOutPutFile, first_file, outputfile);
return true;
}
void save_out_info(float start_time, char * outputfile)
{
if (fp_out_info) {
float duration = get_file_duration(outputfile, false);
fprintf(fp_out_info, "%.3f %.3f %s\n", start_time, duration, outputfile);
}
}
int process_va_files()
{
char outputfile[1024];
vector<media_info> cur_processing;
int nOutPutFile = 0;
float start_time;
bool is_start = true;
string start_file;
while (sorted_infos.size())
{
int channel = sorted_infos[0].channel;
if (0 == channel) {
if (!sorted_infos[1].index == sorted_infos[0].index)
{
split_ch0_for_no_process(cur_processing);
}
else{
get_front_info(1, cur_processing);
}
transcode_files(cur_processing);
}
else if (1 == channel) {
int index = find_video_end();
if (is_ch0_start(index - 1)) {
split_ch0_for_ch1(index - 1, cur_processing);
}
else {
get_front_info(index, cur_processing);
}
merge_audio_video(cur_processing);
}
//if the duration between the processed end and the start of not processed is large than 200 ms, reopen a new file
if (is_start){
start_time = cur_processing[0].start_time;
start_file = cur_processing[0].name;
is_start = false;
}
if (is_need_output(nOutPutFile, cur_processing, start_file.c_str(), outputfile)){
nOutPutFile++;
concate_files_and_adjust_timecode(outputfile);
save_out_info(start_time, outputfile);
is_start = true;
}
}
return 0;
}
int process_files()
{
//don't split video, for a video, using merged audios to mix with it
//for audio, mix with video or jpg
char outputfile[1024];
init();
if (!media_files.size()){
return 0;
}
fp_out_info = fopen(out_info_file, "wt");
process_va_files();
if (fp_out_info) {
fclose(fp_out_info);
}
return 0;
}
int readfile(char * filename)
{
ifstream fin(filename);
if (!fin) {
return -1;
}
const int LINE_LENGTH = 1000;
char str[LINE_LENGTH];
while (fin.getline(str, LINE_LENGTH))
{
vector < string > res;
split(str, " ", res);
if (res.size() >= 3) {
if (res[2] == "create"){
addinfo(res[0], res[1], true);
}
else if (res[2] == "close") {
addinfo(res[0], res[1], false);
}
}
}
return 0;
}
// parse the filename like 4165000_20180203013327202.aac
#define get_sub_str_to_x(x , source, len, result) strncpy(x, source, len); x[len] = 0; source += len; result = atoi(x);
time_t time_sec_1970_base = 0;
float get_start_time_from_filename(const char * filename)
{
int year, month, day, hour, min, sec, minsec;
char buf[5];
const char * start = strstr(filename, "_");
start++;
const char * end = strstr(start, ".");
get_sub_str_to_x(buf, start, 4, year);
get_sub_str_to_x(buf, start, 2, month);
get_sub_str_to_x(buf, start, 2, day);
get_sub_str_to_x(buf, start, 2, hour);
get_sub_str_to_x(buf, start, 2, min);
get_sub_str_to_x(buf, start, 2, sec);
get_sub_str_to_x(buf, start, 3, minsec);
time_t t = calc_sec1970(year, month, day, hour, min, sec);
if (!time_sec_1970_base) {
time_sec_1970_base = calc_sec1970(year, month, day, 0, 0, 0);
}
t -= time_sec_1970_base;
return (float)(t) + minsec / 1000.0;
}
int readfile(char * filename, int channel)
{
ifstream fin(filename);
if (!fin) {
return -1;
}
const int LINE_LENGTH = 1000;
char str[LINE_LENGTH];
float start_time;
bool bstart_time = true;
while (fin.getline(str, LINE_LENGTH))
{
vector < string > res;
split(str, " ", res);
if (res.size() == 3) {
if (bstart_time) {
start_time = get_start_time_from_filename(res[2].c_str());
bstart_time = false;
}
addinfo(atof(res[0].c_str()) + start_time ,atof(res[1].c_str()) , res[2], channel);
}
}
return 0;
}
void load_codec_param()
{
strcpy(acodec_param, default_acodec_param);
strcpy(vcodec_param, default_vcodec_param);
strcpy(av_codec_param, default_av_codec_param);
strcpy(pip_param, default_pip_param);
char cfgfile[1024];
strcpy(cfgfile, cfg_path);
strcat(cfgfile, "merge_av.cfg");
ifstream fin(cfgfile);
if (!fin) {
return;
}
const int LINE_LENGTH = 1000;
char str[LINE_LENGTH];
str[0] = 0;
if (fin.getline(str, LINE_LENGTH))
{
printf("\nload video codec from %s: %s\n", cfgfile, str);
strcpy(vcodec_param, str);
}
str[0] = 0;
if (fin.getline(str, LINE_LENGTH))
{
printf("load audio codec from %s: %s\n", cfgfile, str);
strcpy(acodec_param, str);
}
str[0] = 0;
if (fin.getline(str, LINE_LENGTH))
{
printf("load av codec from %s: %s\n", cfgfile, str);
strcpy(av_codec_param, str);
}
str[0] = 0;
if (fin.getline(str, LINE_LENGTH))
{
printf("load av codec from %s: %s\n", cfgfile, str);
strcpy(pip_param, str);
}
}
void get_outinfo_file_name(char * input1 , char * input2)
{
strcpy(out_info_file, input1);
char * p = strstr(out_info_file, ".");
if (p) {
*p = 0;
}
strcat(out_info_file, "__");
strcat(out_info_file, input2);
}
int main(int argc, char * argv[])
{
if (argc < 3) {
printf(" pip 1.0.0\n");
printf(" run ffmpeg to merge video files to one pip video according to the processed record info file,\nusage:");
printf("\n %s record_info_out_filename1 record_info_out_filename2 [-p] [-k]", argv[0]);
printf("\n -p :only print the command,don't run ffmpeg");
printf("\n -k :keep the temp files\n");
return -1;
}
if (readfile(argv[1], 0) < 0) {
printf("open file: %s error", argv[1]);
return -2;
}
if (readfile(argv[2], 1) < 0) {
printf("open file: %s error", argv[1]);
return -2;
}
for (int i = 3; i < argc; i++){
if (!strcmp(argv[i], "-p")){
only_print = true;
}
else if (!strcmp(argv[i], "-k")){
keep_tmp_files = true;
}
}
get_outinfo_file_name(argv[1], argv[2]);
get_config_path();
load_codec_param();
process_files();
return 0;
}
... ...
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{7D6B14AD-7FD2-45F1-A196-A2455406D4FB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>pip</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="pip.cpp" />
<ClCompile Include="tools.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="pip.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="tools.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
</Project>
\ No newline at end of file
... ...
#include "tools.h"
#define is_leap_year(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
/* 计算某个日期距1970年1月1日0时0分0秒的秒数 */
time_t calc_sec1970(int Y, int M, int D, int h, int m, int s)
{
int i = 0;
int sec = 0;
int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
/* 年计算 */
for (i = 1970; i < Y; i++)
{
if (is_leap_year(i))
sec += 366 * 24 * 60 * 60;
else
sec += 365 * 24 * 60 * 60;
}
/* 月计算 */
for (i = 1; i < M; i++)
{
sec += days[i] * 24 * 60 * 60;
if (i == 2 && is_leap_year(Y))
{
sec += 24 * 60 * 60;
}
}
/* 天计算 */
sec += (D - 1) * 24 * 60 * 60;
/* 时分秒计算 */
sec += h * 60 * 60 + m * 60 + s;
return sec;
}
\ No newline at end of file
... ...
#ifndef TOOLS_H
#define TOOLS_H
#include <time.h>
time_t calc_sec1970(int Y, int M, int D, int h, int m, int s);
#endif
\ No newline at end of file
... ...