胡斌

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

#include "AVTranscoder.h"
#include "tools.h"
#include "ConfigFile.h"
extern CConfigFile _codec_config;
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
... ... @@ -227,9 +230,8 @@ int CAVTranscoder::open_output_file(const char *filename)
return AVERROR_INVALIDDATA;
}
/* In this example, we transcode to same properties (picture size,
* sample rate etc.). These properties can be changed for output
* streams easily using filters */
printf("\n video parameters:");
enc_ctx->height = _nOutputHeight;
enc_ctx->width = _nOutputWidth;
enc_ctx->sample_aspect_ratio.den = 1;
... ... @@ -238,21 +240,58 @@ int CAVTranscoder::open_output_file(const char *filename)
enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
/* video time_base can be set to whatever is handy and supported by encoder */
enc_ctx->time_base.num = 1;
enc_ctx->time_base.den = 20;
enc_ctx->gop_size = 20;
enc_ctx->time_base.den = _codec_config.get_int("fps", 20);
printf("\n fps: %d", enc_ctx->time_base.den);
enc_ctx->gop_size = _codec_config.get_int("gop_size", enc_ctx->time_base.den);
printf("\n gop_size: %d", enc_ctx->gop_size);
enc_ctx->me_range = 16;
enc_ctx->max_qdiff = 4;
enc_ctx->qmin = 10;
enc_ctx->qmax = 30;
enc_ctx->qcompress = 0.6f;
enc_ctx->me_range = _codec_config.get_int("me_range", 16);
printf("\n me_range: %d", enc_ctx->me_range);
enc_ctx->max_qdiff = _codec_config.get_int("max_qdiff", 4);
printf("\n max_qdiff: %d", enc_ctx->max_qdiff);
enc_ctx->qmin = _codec_config.get_int("qmin", 10);
printf("\n qmin: %d", enc_ctx->qmin);
enc_ctx->qmax = _codec_config.get_int("qmax", 30);
printf("\n qmax: %d", enc_ctx->qmax);
enc_ctx->qcompress = _codec_config.get_float("qcompress", 0.6f);
printf("\n qcompress: %.2f", enc_ctx->qcompress);
enc_ctx->framerate.den = 20;
enc_ctx->framerate.den = enc_ctx->time_base.den;
enc_ctx->framerate.num = 1;
enc_ctx->max_b_frames = 0;
enc_ctx->max_b_frames = _codec_config.get_int("max_b_frames", 0);
printf("\n max_b_frames: %d", enc_ctx->max_b_frames);
enc_ctx->bit_rate = _codec_config.get_int("bit_rate", 256000);
printf("\n bit_rate: %d", enc_ctx->bit_rate);
enc_ctx->rc_max_rate = _codec_config.get_int("rc_max_rate", 0);
printf("\n rc_max_rate: %d", enc_ctx->rc_max_rate);
enc_ctx->rc_min_rate = _codec_config.get_int("rc_min_rate", 0);
printf("\n rc_min_rate: %d", enc_ctx->rc_min_rate);
enc_ctx->rc_buffer_size = _codec_config.get_int("rc_buffer_size", enc_ctx->rc_max_rate);
printf("\n rc_buffer_size: %d", enc_ctx->rc_buffer_size);
AVDictionary * d = NULL;
av_dict_set(&d, "preset", "ultrafast", 0);
std::string preset = _codec_config.get_string("preset", "ultrafast");
if (preset != "none") {
printf("\n preset: %s", preset.c_str());
av_dict_set(&d, "preset", preset.c_str(), 0);
}
std::string tune = _codec_config.get_string("tune", "none");
if (tune != "none") {
printf("\n tune: %s", tune.c_str());
av_dict_set(&d, "tune", tune.c_str(), 0);
}
std::string profile = _codec_config.get_string("profile", "none");
if (profile != "none") {
printf("\n profile: %s", profile.c_str());
av_dict_set(&d, "profile", profile.c_str(), 0);
}
printf("\n-----------------------------------");
/* Third parameter can be used to pass settings to encoder */
ret = avcodec_open2(enc_ctx, encoder, &d);
if (ret < 0) {
... ... @@ -261,20 +300,24 @@ int CAVTranscoder::open_output_file(const char *filename)
}
}
else {
printf("\n audio parameters:");
encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);;
if (!encoder) {
av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n");
return AVERROR_INVALIDDATA;
}
enc_ctx->sample_rate = 48000;
enc_ctx->sample_rate = _codec_config.get_int("a_sample_rate", 48000);
printf("\n sample_rate: %d", enc_ctx->sample_rate);
enc_ctx->channel_layout = AV_CH_LAYOUT_MONO;
enc_ctx->channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_MONO);
/* take first format from list of supported formats */
enc_ctx->sample_fmt = PCM_FORMAT_FOR_AAC_ENCODE; //AV_SAMPLE_FMT_FLTP;
enc_ctx->time_base.num = 1;
enc_ctx->time_base.den = enc_ctx->sample_rate;
enc_ctx->bit_rate = 64000;
printf("\n bit_rate: %d", enc_ctx->bit_rate);
enc_ctx->bit_rate = _codec_config.get_int("a_bit_rate", 64000);
/* Third parameter can be used to pass settings to encoder */
printf("\n-----------------------------------");
ret = avcodec_open2(enc_ctx, encoder, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open audio encoder for stream #%u\n", i);
... ...
#include "ConfigFile.h"
#include <iostream>
#include <fstream>
using namespace std;
CConfigFile::CConfigFile()
{
}
CConfigFile::~CConfigFile()
{
}
std::string& trim(std::string &s)
{
if (s.empty())
{
return s;
}
s.erase(0, s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + 1);
return s;
}
int CConfigFile::load(const char * filename)
{
ifstream fin(filename);
if (!fin) {
return -1;
}
const int LINE_LENGTH = 1000;
char str[LINE_LENGTH];
while (fin.getline(str, LINE_LENGTH))
{
char * p = str;
while (*p == 0x20 || *p == 0x9){
p++;//bypass space and tab
}
if (*p == ';' || *p == '#'){
continue;//bypass the comment line
}
std::string linestr = p;
string::size_type position = linestr.find('=');
if (position != linestr.npos) {
string item = linestr.substr(0, position);
int value_len = linestr.length() - position;
if (value_len > 0) {
string value = linestr.substr(position + 1, value_len);
trim(item);
trim(value);
_configs[item] = value;
}
}
}
return 0;
}
std::string CConfigFile::lookup(const char * item)
{
map<string, string>::iterator it = _configs.find(item);
if (it != _configs.end()) {
return (*it).second;
}
return "";
}
int CConfigFile::get_int(const char * item, int def)
{
std::string value = lookup(item);
if (value.length() > 0) {
return atoi(value.c_str());
}
else
{
return def;
}
}
float CConfigFile::get_float(const char * item, float def)
{
std::string value = lookup(item);
if (value.length() > 0) {
return atof(value.c_str());
}
else
{
return def;
}
}
std::string CConfigFile::get_string(const char * item, const char * def)
{
std::string value = lookup(item);
if (value.length() > 0) {
return value;
}
else
{
return def;
}
}
... ...
#pragma once
#include <string>
#include <map>
class CConfigFile
{
public:
CConfigFile();
~CConfigFile();
int load(const char * filename);
std::string lookup(const char *item);
int get_int(const char * item, int def);
float get_float(const char * item, float def);
std::string get_string(const char * item, const char * def);
protected:
std::map<std::string, std::string> _configs;
};
... ...
... ... @@ -3,7 +3,7 @@
读入合屏信息文件,合成画中画视频。
使用方法:
merge_pip merge_info.txt [-t {0,1,2}]
merge_pip merge_info.txt [-t {0,1,2}] [-c codec.cfg]
其中merge_info.txt为合屏信息文件,格式如下:
teacher:
... ... @@ -31,6 +31,22 @@ student:下面是学生的录像信息文件,一个文件名一行
2 为使用一对多布局
如果不加-t,则为程序自动选择合屏布局
-c 为可选参数,后面为编码配置文件名。缺省的编码配置文件名为merge_pip_codec.cfg。在windows系统里,与merge_av.exe放在同一目录。在linux下,放在HOME目录下的merge_av目录。
merge_pip_codec.cfg主要编码参数:
#帧率
fps = 20
#关键帧间隔,默认与fps一致,即每秒一个关键帧
gop_size = 20
#视频码率
bit_rate = 256000
;视频预设值编码参数: ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo
preset = ultrafast
#音频采样率
a_sample_rate = 48000
#音频码率
a_bit_rate = 64000
合屏后生成完成信息文件,文件名为"m_" + 输入文件名" + ".txt",合成的mp4文件名为"m_" + 输入文件名" + ".mp4"
如merge_pip 1.txt
生成的完成信息文件是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
1.没有老师,但是有两个学生时,默认使用一对多布局
2.一对一时,老师和学生的视频尺寸不同时,合成的视频高度取老师视频高度加上学生视频高度(之前版本假定老师和学生视频大小一致,使用的是最大高度的二倍)
3.一对多时,支持学生的视频尺寸不一致的情况(之前版本假定只有一种视频尺寸,其它尺寸视为异常)
4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡
\ No newline at end of file
4.一对多时,最多只在老师视频下部排4个学生,多于4个学生的情况,扩大合成视频的高度,把学生视频排列在老师视频下方,保证老师视频部分最多只有一排学生视频,避免老师视频被过度遮挡
V2.0.4
1.支持读取编码配置文件,用于改变编码配置
\ No newline at end of file
... ...
... ... @@ -9,6 +9,7 @@
#include <deque>
#include "tools.h"
#include "AVTranscoder.h"
#include "ConfigFile.h"
bool only_print = false;
bool keep_tmp_files = false;
... ... @@ -50,11 +51,11 @@ void run_shell_cmd(const char * cmd)
}
}
char exe_path[1024] = { 0 };
#ifdef WIN32
#include <Windows.h>
char exe_path[MAX_PATH] = { 0 };
int GetExePath()
{
char path_buffer[MAX_PATH] = "";
... ... @@ -70,15 +71,37 @@ int GetExePath()
strcat(exe_path, dir);
return 0;
}
#else
int GetExePath()
{
char path[1024];
int cnt = readlink("/proc/self/exe", path, 1024);
if (cnt < 0 || cnt >= 1024)
{
return -1;
}
for (int i = cnt; i >= 0; --i)
{
if (path[i] == '/')
{
path[i + 1] = '\0';
break;
}
}
strcpy(exe_path, path);
return 0;
}
#endif
char cfg_path[1024];
void get_config_path(){
#ifdef WIN32
GetExePath();
strcpy(cfg_path, exe_path);
#else
#if 0
strcpy(cfg_path, getenv("HOME"));
strcat(cfg_path, "/merge_av/");
#endif
... ... @@ -957,6 +980,10 @@ int readfile(const char * filename, media_role role)
vector<string> all_input_files_for_pip;
CConfigFile _codec_config;
char user_codec_cfg[1024] = { 0 };
void load_codec_param()
{
strcpy(acodec_param, default_acodec_param);
... ... @@ -968,43 +995,19 @@ void load_codec_param()
char cfgfile[1024];
strcpy(cfgfile, cfg_path);
strcat(cfgfile, "merge_pip.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);
if (user_codec_cfg[0]) {
strcat(cfgfile, user_codec_cfg);
}
str[0] = 0;
if (fin.getline(str, LINE_LENGTH))
{
printf("load av codec from %s: %s\n", cfgfile, str);
strcpy(av_codec_param, str);
else {
strcat(cfgfile, "merge_pip_codec.cfg");
}
str[0] = 0;
if (fin.getline(str, LINE_LENGTH))
{
printf("load pip codec from %s: %s\n", cfgfile, str);
strcpy(pip_param, str);
if (_codec_config.load(cfgfile) < 0) {
printf("open codec config file fail: %s", cfgfile);
}
str[0] = 0;
if (fin.getline(str, LINE_LENGTH))
{
printf("load pip1 codec from %s: %s\n", cfgfile, str);
strcpy(pip1_param, str);
else {
printf("open codec config file success: %s", cfgfile);
}
}
... ... @@ -1198,17 +1201,13 @@ int process_av_files(char * record_info, int piptype)
int main(int argc, char * argv[])
{
if (argc < 2) {
printf(" merge_pip 2.0.3\n");
printf(" merge_pip 2.0.4\n");
printf(" merge video files to one pip video according to record info file,\nusage:");
printf("\n %s record_info_filename [-t {0,1,2}]", argv[0]);
printf("\n %s record_info_filename [-t {0,1,2}] [-c codec.cfg]", argv[0]);
printf("\n\n");
return -1;
}
//get_config_path();
//load_codec_param();
int piptype = 0;
for (int i = 2; i < argc; i++){
if (!strcmp(argv[i], "-t")){
... ... @@ -1219,7 +1218,20 @@ int main(int argc, char * argv[])
}
piptype = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-c")){
i++;
if (i > argc) {
printf("error,should have codec config file name after -c");
return -2;
}
strcpy(user_codec_cfg,argv[i]);
}
}
get_config_path();
load_codec_param();
return process_av_files(argv[1], piptype);
}
... ...
... ... @@ -86,6 +86,7 @@
<ItemGroup>
<ClCompile Include="AudioDecoder.cpp" />
<ClCompile Include="AVDecoder.cpp" />
<ClCompile Include="ConfigFile.cpp" />
<ClCompile Include="merge_pip.cpp" />
<ClCompile Include="tools.cpp" />
<ClCompile Include="VideoDecoder.cpp" />
... ... @@ -94,6 +95,7 @@
<ItemGroup>
<ClInclude Include="AudioDecoder.h" />
<ClInclude Include="AVDecoder.h" />
<ClInclude Include="ConfigFile.h" />
<ClInclude Include="media_info.h" />
<ClInclude Include="tools.h" />
<ClInclude Include="VideoDecoder.h" />
... ...
... ... @@ -36,6 +36,9 @@
<ClCompile Include="merge_pip.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="ConfigFile.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="VideoDecoder.h">
... ... @@ -56,5 +59,8 @@
<ClInclude Include="tools.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="ConfigFile.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
... ...