胡斌

V2.0.4 支持读取编码配置文件,用于改变编码配置

1 #include "AVTranscoder.h" 1 #include "AVTranscoder.h"
2 #include "tools.h" 2 #include "tools.h"
  3 +#include "ConfigFile.h"
  4 +
  5 +extern CConfigFile _codec_config;
3 6
4 #ifndef max 7 #ifndef max
5 #define max(a,b) (((a) > (b)) ? (a) : (b)) 8 #define max(a,b) (((a) > (b)) ? (a) : (b))
@@ -227,9 +230,8 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -227,9 +230,8 @@ int CAVTranscoder::open_output_file(const char *filename)
227 return AVERROR_INVALIDDATA; 230 return AVERROR_INVALIDDATA;
228 } 231 }
229 232
230 - /* In this example, we transcode to same properties (picture size,  
231 - * sample rate etc.). These properties can be changed for output  
232 - * streams easily using filters */ 233 + printf("\n video parameters:");
  234 +
233 enc_ctx->height = _nOutputHeight; 235 enc_ctx->height = _nOutputHeight;
234 enc_ctx->width = _nOutputWidth; 236 enc_ctx->width = _nOutputWidth;
235 enc_ctx->sample_aspect_ratio.den = 1; 237 enc_ctx->sample_aspect_ratio.den = 1;
@@ -238,21 +240,58 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -238,21 +240,58 @@ int CAVTranscoder::open_output_file(const char *filename)
238 enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P; 240 enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
239 /* video time_base can be set to whatever is handy and supported by encoder */ 241 /* video time_base can be set to whatever is handy and supported by encoder */
240 enc_ctx->time_base.num = 1; 242 enc_ctx->time_base.num = 1;
241 - enc_ctx->time_base.den = 20;  
242 - enc_ctx->gop_size = 20; 243 + enc_ctx->time_base.den = _codec_config.get_int("fps", 20);
  244 + printf("\n fps: %d", enc_ctx->time_base.den);
  245 + enc_ctx->gop_size = _codec_config.get_int("gop_size", enc_ctx->time_base.den);
  246 + printf("\n gop_size: %d", enc_ctx->gop_size);
243 247
244 - enc_ctx->me_range = 16;  
245 - enc_ctx->max_qdiff = 4;  
246 - enc_ctx->qmin = 10;  
247 - enc_ctx->qmax = 30;  
248 - enc_ctx->qcompress = 0.6f; 248 + enc_ctx->me_range = _codec_config.get_int("me_range", 16);
  249 + printf("\n me_range: %d", enc_ctx->me_range);
  250 + enc_ctx->max_qdiff = _codec_config.get_int("max_qdiff", 4);
  251 + printf("\n max_qdiff: %d", enc_ctx->max_qdiff);
  252 + enc_ctx->qmin = _codec_config.get_int("qmin", 10);
  253 + printf("\n qmin: %d", enc_ctx->qmin);
  254 + enc_ctx->qmax = _codec_config.get_int("qmax", 30);
  255 + printf("\n qmax: %d", enc_ctx->qmax);
  256 +
  257 + enc_ctx->qcompress = _codec_config.get_float("qcompress", 0.6f);
  258 + printf("\n qcompress: %.2f", enc_ctx->qcompress);
249 259
250 - enc_ctx->framerate.den = 20; 260 + enc_ctx->framerate.den = enc_ctx->time_base.den;
251 enc_ctx->framerate.num = 1; 261 enc_ctx->framerate.num = 1;
252 - enc_ctx->max_b_frames = 0; 262 + enc_ctx->max_b_frames = _codec_config.get_int("max_b_frames", 0);
  263 + printf("\n max_b_frames: %d", enc_ctx->max_b_frames);
  264 +
  265 + enc_ctx->bit_rate = _codec_config.get_int("bit_rate", 256000);
  266 + printf("\n bit_rate: %d", enc_ctx->bit_rate);
  267 + enc_ctx->rc_max_rate = _codec_config.get_int("rc_max_rate", 0);
  268 + printf("\n rc_max_rate: %d", enc_ctx->rc_max_rate);
  269 + enc_ctx->rc_min_rate = _codec_config.get_int("rc_min_rate", 0);
  270 + printf("\n rc_min_rate: %d", enc_ctx->rc_min_rate);
  271 + enc_ctx->rc_buffer_size = _codec_config.get_int("rc_buffer_size", enc_ctx->rc_max_rate);
  272 + printf("\n rc_buffer_size: %d", enc_ctx->rc_buffer_size);
253 273
254 AVDictionary * d = NULL; 274 AVDictionary * d = NULL;
255 - av_dict_set(&d, "preset", "ultrafast", 0); 275 + std::string preset = _codec_config.get_string("preset", "ultrafast");
  276 + if (preset != "none") {
  277 + printf("\n preset: %s", preset.c_str());
  278 + av_dict_set(&d, "preset", preset.c_str(), 0);
  279 + }
  280 +
  281 + std::string tune = _codec_config.get_string("tune", "none");
  282 + if (tune != "none") {
  283 + printf("\n tune: %s", tune.c_str());
  284 + av_dict_set(&d, "tune", tune.c_str(), 0);
  285 + }
  286 +
  287 + std::string profile = _codec_config.get_string("profile", "none");
  288 + if (profile != "none") {
  289 + printf("\n profile: %s", profile.c_str());
  290 + av_dict_set(&d, "profile", profile.c_str(), 0);
  291 + }
  292 +
  293 + printf("\n-----------------------------------");
  294 +
256 /* Third parameter can be used to pass settings to encoder */ 295 /* Third parameter can be used to pass settings to encoder */
257 ret = avcodec_open2(enc_ctx, encoder, &d); 296 ret = avcodec_open2(enc_ctx, encoder, &d);
258 if (ret < 0) { 297 if (ret < 0) {
@@ -261,20 +300,24 @@ int CAVTranscoder::open_output_file(const char *filename) @@ -261,20 +300,24 @@ int CAVTranscoder::open_output_file(const char *filename)
261 } 300 }
262 } 301 }
263 else { 302 else {
  303 + printf("\n audio parameters:");
264 encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);; 304 encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);;
265 if (!encoder) { 305 if (!encoder) {
266 av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n"); 306 av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n");
267 return AVERROR_INVALIDDATA; 307 return AVERROR_INVALIDDATA;
268 } 308 }
269 - enc_ctx->sample_rate = 48000; 309 + enc_ctx->sample_rate = _codec_config.get_int("a_sample_rate", 48000);
  310 + printf("\n sample_rate: %d", enc_ctx->sample_rate);
270 enc_ctx->channel_layout = AV_CH_LAYOUT_MONO; 311 enc_ctx->channel_layout = AV_CH_LAYOUT_MONO;
271 enc_ctx->channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO); 312 enc_ctx->channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);
272 /* take first format from list of supported formats */ 313 /* take first format from list of supported formats */
273 enc_ctx->sample_fmt = PCM_FORMAT_FOR_AAC_ENCODE; //AV_SAMPLE_FMT_FLTP; 314 enc_ctx->sample_fmt = PCM_FORMAT_FOR_AAC_ENCODE; //AV_SAMPLE_FMT_FLTP;
274 enc_ctx->time_base.num = 1; 315 enc_ctx->time_base.num = 1;
275 enc_ctx->time_base.den = enc_ctx->sample_rate; 316 enc_ctx->time_base.den = enc_ctx->sample_rate;
276 - enc_ctx->bit_rate = 64000; 317 + printf("\n bit_rate: %d", enc_ctx->bit_rate);
  318 + enc_ctx->bit_rate = _codec_config.get_int("a_bit_rate", 64000);
277 /* Third parameter can be used to pass settings to encoder */ 319 /* Third parameter can be used to pass settings to encoder */
  320 + printf("\n-----------------------------------");
278 ret = avcodec_open2(enc_ctx, encoder, NULL); 321 ret = avcodec_open2(enc_ctx, encoder, NULL);
279 if (ret < 0) { 322 if (ret < 0) {
280 av_log(NULL, AV_LOG_ERROR, "Cannot open audio encoder for stream #%u\n", i); 323 av_log(NULL, AV_LOG_ERROR, "Cannot open audio encoder for stream #%u\n", i);
  1 +#include "ConfigFile.h"
  2 +#include <iostream>
  3 +#include <fstream>
  4 +using namespace std;
  5 +
  6 +CConfigFile::CConfigFile()
  7 +{
  8 +}
  9 +
  10 +
  11 +CConfigFile::~CConfigFile()
  12 +{
  13 +}
  14 +
  15 +std::string& trim(std::string &s)
  16 +{
  17 + if (s.empty())
  18 + {
  19 + return s;
  20 + }
  21 +
  22 + s.erase(0, s.find_first_not_of(" "));
  23 + s.erase(s.find_last_not_of(" ") + 1);
  24 + return s;
  25 +}
  26 +
  27 +int CConfigFile::load(const char * filename)
  28 +{
  29 + ifstream fin(filename);
  30 + if (!fin) {
  31 + return -1;
  32 + }
  33 +
  34 + const int LINE_LENGTH = 1000;
  35 + char str[LINE_LENGTH];
  36 + while (fin.getline(str, LINE_LENGTH))
  37 + {
  38 + char * p = str;
  39 + while (*p == 0x20 || *p == 0x9){
  40 + p++;//bypass space and tab
  41 + }
  42 + if (*p == ';' || *p == '#'){
  43 + continue;//bypass the comment line
  44 + }
  45 +
  46 + std::string linestr = p;
  47 +
  48 + string::size_type position = linestr.find('=');
  49 + if (position != linestr.npos) {
  50 + string item = linestr.substr(0, position);
  51 + int value_len = linestr.length() - position;
  52 + if (value_len > 0) {
  53 + string value = linestr.substr(position + 1, value_len);
  54 + trim(item);
  55 + trim(value);
  56 + _configs[item] = value;
  57 + }
  58 + }
  59 + }
  60 + return 0;
  61 +}
  62 +
  63 +std::string CConfigFile::lookup(const char * item)
  64 +{
  65 + map<string, string>::iterator it = _configs.find(item);
  66 + if (it != _configs.end()) {
  67 + return (*it).second;
  68 + }
  69 + return "";
  70 +}
  71 +
  72 +int CConfigFile::get_int(const char * item, int def)
  73 +{
  74 + std::string value = lookup(item);
  75 + if (value.length() > 0) {
  76 + return atoi(value.c_str());
  77 + }
  78 + else
  79 + {
  80 + return def;
  81 + }
  82 +}
  83 +
  84 +float CConfigFile::get_float(const char * item, float def)
  85 +{
  86 + std::string value = lookup(item);
  87 + if (value.length() > 0) {
  88 + return atof(value.c_str());
  89 + }
  90 + else
  91 + {
  92 + return def;
  93 + }
  94 +}
  95 +
  96 +std::string CConfigFile::get_string(const char * item, const char * def)
  97 +{
  98 + std::string value = lookup(item);
  99 + if (value.length() > 0) {
  100 + return value;
  101 + }
  102 + else
  103 + {
  104 + return def;
  105 + }
  106 +}
  1 +#pragma once
  2 +#include <string>
  3 +#include <map>
  4 +
  5 +class CConfigFile
  6 +{
  7 +public:
  8 + CConfigFile();
  9 + ~CConfigFile();
  10 + int load(const char * filename);
  11 + std::string lookup(const char *item);
  12 + int get_int(const char * item, int def);
  13 + float get_float(const char * item, float def);
  14 + std::string get_string(const char * item, const char * def);
  15 +protected:
  16 + std::map<std::string, std::string> _configs;
  17 +};
  18 +
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 读入合屏信息文件,合成画中画视频。 3 读入合屏信息文件,合成画中画视频。
4 4
5 使用方法: 5 使用方法:
6 -merge_pip merge_info.txt [-t {0,1,2}] 6 +merge_pip merge_info.txt [-t {0,1,2}] [-c codec.cfg]
7 其中merge_info.txt为合屏信息文件,格式如下: 7 其中merge_info.txt为合屏信息文件,格式如下:
8 8
9 teacher: 9 teacher:
@@ -31,6 +31,22 @@ student:下面是学生的录像信息文件,一个文件名一行 @@ -31,6 +31,22 @@ student:下面是学生的录像信息文件,一个文件名一行
31 2 为使用一对多布局 31 2 为使用一对多布局
32 如果不加-t,则为程序自动选择合屏布局 32 如果不加-t,则为程序自动选择合屏布局
33 33
  34 +-c 为可选参数,后面为编码配置文件名。缺省的编码配置文件名为merge_pip_codec.cfg。在windows系统里,与merge_av.exe放在同一目录。在linux下,放在HOME目录下的merge_av目录。
  35 +merge_pip_codec.cfg主要编码参数:
  36 +#帧率
  37 + fps = 20
  38 +#关键帧间隔,默认与fps一致,即每秒一个关键帧
  39 + gop_size = 20
  40 +#视频码率
  41 + bit_rate = 256000
  42 +;视频预设值编码参数: ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo
  43 + preset = ultrafast
  44 +#音频采样率
  45 + a_sample_rate = 48000
  46 + #音频码率
  47 + a_bit_rate = 64000
  48 +
  49 +
34 合屏后生成完成信息文件,文件名为"m_" + 输入文件名" + ".txt",合成的mp4文件名为"m_" + 输入文件名" + ".mp4" 50 合屏后生成完成信息文件,文件名为"m_" + 输入文件名" + ".txt",合成的mp4文件名为"m_" + 输入文件名" + ".mp4"
35 如merge_pip 1.txt 51 如merge_pip 1.txt
36 生成的完成信息文件是m_1.txt,m_1.txt只有一行,记录输出的mp4文件名(m_1.mp4)、参与合成m_1.mp4的第一个媒体文件名(用于帮助确认m_1.mp4的开始时间)及mp4的时长。下面是一个实际的m_1.txt内容: 52 生成的完成信息文件是m_1.txt,m_1.txt只有一行,记录输出的mp4文件名(m_1.mp4)、参与合成m_1.mp4的第一个媒体文件名(用于帮助确认m_1.mp4的开始时间)及mp4的时长。下面是一个实际的m_1.txt内容:
@@ -49,4 +65,7 @@ V2.0.3 @@ -49,4 +65,7 @@ V2.0.3
49 1.没有老师,但是有两个学生时,默认使用一对多布局 65 1.没有老师,但是有两个学生时,默认使用一对多布局
50 2.一对一时,老师和学生的视频尺寸不同时,合成的视频高度取老师视频高度加上学生视频高度(之前版本假定老师和学生视频大小一致,使用的是最大高度的二倍) 66 2.一对一时,老师和学生的视频尺寸不同时,合成的视频高度取老师视频高度加上学生视频高度(之前版本假定老师和学生视频大小一致,使用的是最大高度的二倍)
51 3.一对多时,支持学生的视频尺寸不一致的情况(之前版本假定只有一种视频尺寸,其它尺寸视为异常) 67 3.一对多时,支持学生的视频尺寸不一致的情况(之前版本假定只有一种视频尺寸,其它尺寸视为异常)
52 -4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡  
  68 +4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡
  69 +
  70 +V2.0.4
  71 +1.支持读取编码配置文件,用于改变编码配置
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 #include <deque> 9 #include <deque>
10 #include "tools.h" 10 #include "tools.h"
11 #include "AVTranscoder.h" 11 #include "AVTranscoder.h"
  12 +#include "ConfigFile.h"
12 13
13 bool only_print = false; 14 bool only_print = false;
14 bool keep_tmp_files = false; 15 bool keep_tmp_files = false;
@@ -50,11 +51,11 @@ void run_shell_cmd(const char * cmd) @@ -50,11 +51,11 @@ void run_shell_cmd(const char * cmd)
50 } 51 }
51 } 52 }
52 53
  54 +
  55 +char exe_path[1024] = { 0 };
53 #ifdef WIN32 56 #ifdef WIN32
54 #include <Windows.h> 57 #include <Windows.h>
55 58
56 -char exe_path[MAX_PATH] = { 0 };  
57 -  
58 int GetExePath() 59 int GetExePath()
59 { 60 {
60 char path_buffer[MAX_PATH] = ""; 61 char path_buffer[MAX_PATH] = "";
@@ -70,15 +71,37 @@ int GetExePath() @@ -70,15 +71,37 @@ int GetExePath()
70 strcat(exe_path, dir); 71 strcat(exe_path, dir);
71 return 0; 72 return 0;
72 } 73 }
  74 +#else
  75 +int GetExePath()
  76 +{
  77 + char path[1024];
  78 + int cnt = readlink("/proc/self/exe", path, 1024);
  79 + if (cnt < 0 || cnt >= 1024)
  80 + {
  81 + return -1;
  82 + }
  83 +
  84 + for (int i = cnt; i >= 0; --i)
  85 + {
  86 + if (path[i] == '/')
  87 + {
  88 + path[i + 1] = '\0';
  89 + break;
  90 + }
  91 + }
  92 + strcpy(exe_path, path);
  93 + return 0;
  94 +}
73 #endif 95 #endif
74 96
75 char cfg_path[1024]; 97 char cfg_path[1024];
76 98
77 void get_config_path(){ 99 void get_config_path(){
78 -#ifdef WIN32 100 +
79 GetExePath(); 101 GetExePath();
80 strcpy(cfg_path, exe_path); 102 strcpy(cfg_path, exe_path);
81 -#else 103 +
  104 +#if 0
82 strcpy(cfg_path, getenv("HOME")); 105 strcpy(cfg_path, getenv("HOME"));
83 strcat(cfg_path, "/merge_av/"); 106 strcat(cfg_path, "/merge_av/");
84 #endif 107 #endif
@@ -957,6 +980,10 @@ int readfile(const char * filename, media_role role) @@ -957,6 +980,10 @@ int readfile(const char * filename, media_role role)
957 980
958 vector<string> all_input_files_for_pip; 981 vector<string> all_input_files_for_pip;
959 982
  983 +CConfigFile _codec_config;
  984 +
  985 +char user_codec_cfg[1024] = { 0 };
  986 +
960 void load_codec_param() 987 void load_codec_param()
961 { 988 {
962 strcpy(acodec_param, default_acodec_param); 989 strcpy(acodec_param, default_acodec_param);
@@ -968,43 +995,19 @@ void load_codec_param() @@ -968,43 +995,19 @@ void load_codec_param()
968 char cfgfile[1024]; 995 char cfgfile[1024];
969 996
970 strcpy(cfgfile, cfg_path); 997 strcpy(cfgfile, cfg_path);
971 - strcat(cfgfile, "merge_pip.cfg");  
972 998
973 - ifstream fin(cfgfile);  
974 - if (!fin) {  
975 - return;  
976 - }  
977 - const int LINE_LENGTH = 1000;  
978 - char str[LINE_LENGTH];  
979 - str[0] = 0;  
980 - if (fin.getline(str, LINE_LENGTH))  
981 - {  
982 - printf("\nload video codec from %s: %s\n", cfgfile, str);  
983 - strcpy(vcodec_param, str);  
984 - }  
985 - str[0] = 0;  
986 - if (fin.getline(str, LINE_LENGTH))  
987 - {  
988 - printf("load audio codec from %s: %s\n", cfgfile, str);  
989 - strcpy(acodec_param, str); 999 + if (user_codec_cfg[0]) {
  1000 + strcat(cfgfile, user_codec_cfg);
990 } 1001 }
991 - str[0] = 0;  
992 - if (fin.getline(str, LINE_LENGTH))  
993 - {  
994 - printf("load av codec from %s: %s\n", cfgfile, str);  
995 - strcpy(av_codec_param, str); 1002 + else {
  1003 + strcat(cfgfile, "merge_pip_codec.cfg");
996 } 1004 }
997 - str[0] = 0;  
998 - if (fin.getline(str, LINE_LENGTH))  
999 - {  
1000 - printf("load pip codec from %s: %s\n", cfgfile, str);  
1001 - strcpy(pip_param, str); 1005 +
  1006 + if (_codec_config.load(cfgfile) < 0) {
  1007 + printf("open codec config file fail: %s", cfgfile);
1002 } 1008 }
1003 - str[0] = 0;  
1004 - if (fin.getline(str, LINE_LENGTH))  
1005 - {  
1006 - printf("load pip1 codec from %s: %s\n", cfgfile, str);  
1007 - strcpy(pip1_param, str); 1009 + else {
  1010 + printf("open codec config file success: %s", cfgfile);
1008 } 1011 }
1009 } 1012 }
1010 1013
@@ -1198,17 +1201,13 @@ int process_av_files(char * record_info, int piptype) @@ -1198,17 +1201,13 @@ int process_av_files(char * record_info, int piptype)
1198 int main(int argc, char * argv[]) 1201 int main(int argc, char * argv[])
1199 { 1202 {
1200 if (argc < 2) { 1203 if (argc < 2) {
1201 - printf(" merge_pip 2.0.3\n"); 1204 + printf(" merge_pip 2.0.4\n");
1202 printf(" merge video files to one pip video according to record info file,\nusage:"); 1205 printf(" merge video files to one pip video according to record info file,\nusage:");
1203 - printf("\n %s record_info_filename [-t {0,1,2}]", argv[0]); 1206 + printf("\n %s record_info_filename [-t {0,1,2}] [-c codec.cfg]", argv[0]);
1204 printf("\n\n"); 1207 printf("\n\n");
1205 return -1; 1208 return -1;
1206 } 1209 }
1207 1210
1208 - //get_config_path();  
1209 -  
1210 - //load_codec_param();  
1211 -  
1212 int piptype = 0; 1211 int piptype = 0;
1213 for (int i = 2; i < argc; i++){ 1212 for (int i = 2; i < argc; i++){
1214 if (!strcmp(argv[i], "-t")){ 1213 if (!strcmp(argv[i], "-t")){
@@ -1219,7 +1218,20 @@ int main(int argc, char * argv[]) @@ -1219,7 +1218,20 @@ int main(int argc, char * argv[])
1219 } 1218 }
1220 piptype = atoi(argv[i]); 1219 piptype = atoi(argv[i]);
1221 } 1220 }
  1221 + else if (!strcmp(argv[i], "-c")){
  1222 + i++;
  1223 + if (i > argc) {
  1224 + printf("error,should have codec config file name after -c");
  1225 + return -2;
  1226 + }
  1227 + strcpy(user_codec_cfg,argv[i]);
  1228 + }
1222 } 1229 }
1223 1230
  1231 +
  1232 + get_config_path();
  1233 +
  1234 + load_codec_param();
  1235 +
1224 return process_av_files(argv[1], piptype); 1236 return process_av_files(argv[1], piptype);
1225 } 1237 }
@@ -86,6 +86,7 @@ @@ -86,6 +86,7 @@
86 <ItemGroup> 86 <ItemGroup>
87 <ClCompile Include="AudioDecoder.cpp" /> 87 <ClCompile Include="AudioDecoder.cpp" />
88 <ClCompile Include="AVDecoder.cpp" /> 88 <ClCompile Include="AVDecoder.cpp" />
  89 + <ClCompile Include="ConfigFile.cpp" />
89 <ClCompile Include="merge_pip.cpp" /> 90 <ClCompile Include="merge_pip.cpp" />
90 <ClCompile Include="tools.cpp" /> 91 <ClCompile Include="tools.cpp" />
91 <ClCompile Include="VideoDecoder.cpp" /> 92 <ClCompile Include="VideoDecoder.cpp" />
@@ -94,6 +95,7 @@ @@ -94,6 +95,7 @@
94 <ItemGroup> 95 <ItemGroup>
95 <ClInclude Include="AudioDecoder.h" /> 96 <ClInclude Include="AudioDecoder.h" />
96 <ClInclude Include="AVDecoder.h" /> 97 <ClInclude Include="AVDecoder.h" />
  98 + <ClInclude Include="ConfigFile.h" />
97 <ClInclude Include="media_info.h" /> 99 <ClInclude Include="media_info.h" />
98 <ClInclude Include="tools.h" /> 100 <ClInclude Include="tools.h" />
99 <ClInclude Include="VideoDecoder.h" /> 101 <ClInclude Include="VideoDecoder.h" />
@@ -36,6 +36,9 @@ @@ -36,6 +36,9 @@
36 <ClCompile Include="merge_pip.cpp"> 36 <ClCompile Include="merge_pip.cpp">
37 <Filter>源文件</Filter> 37 <Filter>源文件</Filter>
38 </ClCompile> 38 </ClCompile>
  39 + <ClCompile Include="ConfigFile.cpp">
  40 + <Filter>源文件</Filter>
  41 + </ClCompile>
39 </ItemGroup> 42 </ItemGroup>
40 <ItemGroup> 43 <ItemGroup>
41 <ClInclude Include="VideoDecoder.h"> 44 <ClInclude Include="VideoDecoder.h">
@@ -56,5 +59,8 @@ @@ -56,5 +59,8 @@
56 <ClInclude Include="tools.h"> 59 <ClInclude Include="tools.h">
57 <Filter>头文件</Filter> 60 <Filter>头文件</Filter>
58 </ClInclude> 61 </ClInclude>
  62 + <ClInclude Include="ConfigFile.h">
  63 + <Filter>头文件</Filter>
  64 + </ClInclude>
59 </ItemGroup> 65 </ItemGroup>
60 </Project> 66 </Project>