使用c++ 作为脚本语言制作协议转换中心
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用c++ 作为脚本语言制作协议转换中心相关的知识,希望对你有一定的参考价值。
如何使用c++ 作为脚本语言
首先底层可以使用angelscript,这一点无需质疑,不用再造轮子,因为作者做得比较好,测试的例子也非常好,同时,使用angelscript的游戏也是非常多的,下面简单先使用注册main 和测试函数来进行一个协议转换中心的制作,从而使得非c++ 的人员甚至前端也可以使用脚本c++来制作复杂的媒体工具和协议工具。
首先脚本如下所示:
int main()
int x = 10;
int y = 100;
int c = x+y;
string buffer1="";
string buffer2 = buffer1+c;
Print(buffer2);
Print("\\n");
string xstr = tostring(x);
Print(xstr+"\\n");
//rtsp地址和窗口地址
int ret = rtsp("rtsp://192.168.1.129");
string rtspret ="";
rtspret+= ret;
Print(rtspret+"\\n");
return 0;
和c,c++ 一样,main函数是入口,前面是一些测试函数,其中
1 tostring(int num)
2 rtsp(string url)
此2个函数都是自定义函数,也就是我们的api。rtsp函数表明我们需要拉取一个rtsp流,具体要干什么我们后面再说,如果成功则返回0 ,不成功则返回-1;
随着函数的扩展,例如文件系统的扩展,协议的扩展,我们就能做到使用脚本c++来建立程序,由于脚本在外面是txt,随时可以修改,保证了最大的灵活性。
注册函数
如何注册函数呢,在加载anglescript引擎以后,我们就可以注册自己的函数,注意这里并不是万能的,协议转换函数和媒体函数依然是要自己写的,不过是为了灵活性,我们需要把自己的组件完全标准化。
假定我们使用ffmpeg来制作rtsp程序
int rtsp(string &url)
AVFormatContext* format_ctx = avformat_alloc_context();
AVCodecContext* pAVCodecContext_video = nullptr;
AVCodec* pAVCodec_video = nullptr;
AVCodecParameters* pAVCodePar_video = avcodec_parameters_alloc();
AVPacket* pAVPacket = av_packet_alloc(); ;
AVFrame* pAVFrame_video = av_frame_alloc(); AVFrame* pAVFrameRGB32_video = av_frame_alloc();
AVCodecParserContext* pAVCodeParseContext_video = nullptr;
struct SwsContext* pSwsContext_video = nullptr; AVDictionary* opts = nullptr;
int ret = -1;
int numBytes = 0; // 解码后的数据长度
uint8_t* outBuffer = nullptr; // 解码后的数据存放缓存区
// open rtsp: Open an input stream and read the header. The codecs are not opened
//const char* url = "rtsp://admin:genepoint2020@192.168.100.14:554/cam/realmonitor?channel=1&subtype=0";
av_dict_set(&opts, "rtsp_transport", "tcp", 0);
av_dict_set(&opts, "stimeout", "2000000", 0);
// audio/video stream index
int video_stream_index = -1;
ret = avformat_open_input(&format_ctx, url, nullptr, &opts);
if (ret != 0)
fprintf(stderr, "fail to open url: %s, return value: %d\\n", url, ret);
return -1;
// Read packets of a media file to get stream information
ret = avformat_find_stream_info(format_ctx, nullptr);
if (ret < 0)
fprintf(stderr, "fail to get stream information: %d\\n", ret);
return -1;
fprintf(stdout, "Number of elements in AVFormatContext.streams: %d\\n", format_ctx->nb_streams);
for (int i = 0; i < format_ctx->nb_streams; ++i)
const AVStream* stream = format_ctx->streams[i];
fprintf(stdout, "type of the encoded data: %d\\n", stream->codecpar->codec_id);
if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
video_stream_index = i;
pAVCodePar_video = stream->codecpar;
pAVCodec_video = avcodec_find_decoder(stream->codecpar->codec_id);
if (!pAVCodec_video)
video_stream_index = -1;
break;
pAVCodeParseContext_video = av_parser_init(pAVCodec_video->id);
if (!pAVCodeParseContext_video)
video_stream_index = -1;
break;
pAVCodecContext_video = avcodec_alloc_context3(pAVCodec_video);
if (!pAVCodecContext_video)
if (avcodec_open2(pAVCodecContext_video, pAVCodec_video, NULL) < 0)
video_stream_index = -1;
break;
fprintf(stdout, "dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\\n",
stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);
if (video_stream_index == -1)
fprintf(stderr, "no video stream\\n");
return -1;
// 对拿到的原始数据格式进行缩放转换为指定的格式高宽大小
pSwsContext_video = sws_getContext(
pAVCodePar_video->width,
pAVCodePar_video->height,
static_cast<AVPixelFormat>(pAVCodePar_video->format),
pAVCodePar_video->width,
pAVCodePar_video->height,
AV_PIX_FMT_RGBA,
SWS_FAST_BILINEAR,
nullptr,
nullptr,
nullptr
);
numBytes = av_image_get_buffer_size(
AV_PIX_FMT_RGBA,
pAVCodePar_video->width,
pAVCodePar_video->height,
1
);
outBuffer = (uint8_t*)av_malloc(numBytes);
// pAVFrame32的data指针指向了outBuffer
(
pAVFrameRGB32_video->data,
pAVFrameRGB32_video->linesize,
outBuffer,
AV_PIX_FMT_RGBA,
pAVCodePar_video->width,
pAVCodePar_video->height,
1
);
while (1)
ret = av_read_frame(format_ctx, pAVPacket);
if (ret < 0)
fprintf(stderr, "error or end of file: %d\\n", ret);
continue;
if (pAVPacket->stream_index == video_stream_index)
// fprintf(stdout, "video stream, packet size: %d\\n", pAVPacket->size);
ret = avcodec_send_packet(pAVCodecContext_video, pAVPacket);
if (0 != ret)
continue;
while (avcodec_receive_frame(pAVCodecContext_video, pAVFrame_video) == 0)
sws_scale(pSwsContext_video,
(const uint8_t* const*)pAVFrame_video->data,
pAVFrame_video->linesize,
0,
pAVCodePar_video->height,
pAVFrameRGB32_video->data,
pAVFrameRGB32_video->linesize);
//这里得到图像输出
//做其他操作
av_packet_unref(pAVPacket);
av_parser_close(pAVCodeParseContext_video);
av_frame_free(&pAVFrame_video);
av_frame_free(&pAVFrameRGB32_video);
av_free(outBuffer);
av_free(pSwsContext_video);
avcodec_free_context(&pAVCodecContext_video);
avformat_close_input(&format_ctx);
return 0;
上面这个函数如果正常运行是没有返回的,其实不对,这里是作为示例,我们制作一个加的rtsp 函数,简单一点,如下所示
string _to_string(int &y)
string temp= std::to_string(y);
return temp;
//you do here
int _rtsp(string& url)
//your code here
return (int)url.find("/");
两个注册函数完成,下面在引擎里注册一个函数
if( !strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
// Register the functions that the scripts will be allowed to use.
// Note how the return code is validated with an assert(). This helps
// us discover where a problem occurs, and doesn't pollute the code
// with a lot of if's. If an error occurs in release mode it will
// be caught when a script is being built, so it is not necessary
// to do the verification here as well.
r = engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString), asCALL_CDECL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("uint GetSystemTime()", asFUNCTION(timeGetTime), asCALL_STDCALL); assert( r >= 0 );
r = engine->RegisterGlobalFunction("string tostring(int &in)", asFUNCTION(_to_string), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("int rtsp(string &in)", asFUNCTION(_rtsp), asCALL_CDECL); assert(r >= 0);
实现了这些函数就可以在脚本里面使用了。下面是整体代码:
#include <iostream> // cout
#include <assert.h> // assert()
#include <string.h> // strstr()
#ifdef __linux__
#include <sys/time.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#else
#include <conio.h> // kbhit(), getch()
#include <windows.h> // timeGetTime()
#endif
#include <angelscript.h>
#include "../../../add_on/scriptstdstring/scriptstdstring.h"
using namespace std;
#ifdef __linux__
#define UINT unsigned int
typedef unsigned int DWORD;
// Linux doesn't have timeGetTime(), this essentially does the same
// thing, except this is milliseconds since Epoch (Jan 1st 1970) instead
// of system start. It will work the same though...
DWORD timeGetTime()
timeval time;
gettimeofday(&time, NULL);
return time.tv_sec*1000 + time.tv_usec/1000;
// Linux does have a getch() function in the curses library, but it doesn't
// work like it does on DOS. So this does the same thing, with out the need
// of the curses library.
int getch()
struct termios oldt, newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
#endif
// Function prototypes
int RunApplication();
void ConfigureEngine(asIScriptEngine *engine);
int CompileScript(asIScriptEngine *engine);
void PrintString(string &str);
void PrintString_Generic(asIScriptGeneric *gen);
void timeGetTime_Generic(asIScriptGeneric *gen);
string _to_string(int &y);
int _rtsp(string& url);
void LineCallback(asIScriptContext *ctx, DWORD *timeOut);
int main(int argc, char **argv)
RunApplication();
// Wait until the user presses a key
cout << endl << "Press any key to quit." << endl;
while(!getch());
return 0;
void MessageCallback(const asSMessageInfo *msg, void *param)
const char *type = "ERR ";
if( msg->type == asMSGTYPE_WARNING )
type = "WARN";
else if( msg->type == asMSGTYPE_INFORMATION )
type = "INFO";
printf("%s (%d, %d) : %s : %s\\n", msg->section, msg->row, msg->col, type, msg->message);
int RunApplication()
int r;
// Create the script engine
asIScriptEngine *engine = asCreateScriptEngine();
if( engine == 0 )
cout << "Failed to create script engine." << endl;
return -1;
// The script compiler will write any compiler messages to the callback.
engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
// Configure the script engine with all the functions,
// and variables that the script should be able to use.
ConfigureEngine(engine);
// Compile the script code
r = CompileScript(engine);
if( r < 0 )
engine->Release();
return -1;
// Create a context that will execute the script.
asIScriptContext *ctx = engine->CreateContext();
if( ctx == 0 )
cout << "Failed to create the context." << endl;
engine->Release();
return -1;
// We don't want to allow the script to hang the application, e.g. with an
// infinite loop, so we'll use the line callback function to set a timeout
// that will abort the script after a certain time. Before executing the
// script the timeOut variable will be set to the time when the script must
// stop executing.
DWORD timeOut;
r = ctx->SetLineCallback(asFUNCTION(LineCallback), &timeOut, asCALL_CDECL);
if( r < 0 )
cout << "Failed to set the line callback function." << endl;
ctx->Release();
engine->Release();
return -1;
// Find the function for the function we want to execute.
asIScriptFunction *func = engine->GetModule(0)->GetFunctionByDecl("float calc(float, float)");
if( func == 0 )
cout << "The function 'float calc(float, float)' was not found." << endl;
ctx->Release();
engine->Release();
return -1;
// Prepare the script context with the function we wish to execute. Prepare()
// must be called on the context before each new script function that will be
// executed. Note, that if you intend to execute the same function several
// times, it might be a good idea to store the function returned by
// GetFunctionByDecl(), so that this relatively slow call can be skipped.
r = ctx->Prepare(func);
if( r < 0 )
cout << "Failed to prepare the context." << endl;
ctx->Release();
engine->Release();
return -1;
// Now we need to pass the parameters to the script function.
ctx->SetArgFloat(0, 3.14159265359f);
ctx->SetArgFloat(1, 5.71828182846f);
// Set the timeout before executing the function. Give the function 1 sec
// to return before we'll abort it.
timeOut = timeGetTime() + 1000;
// Execute the function
cout << "Executing the script." << endl;
cout << "---" << endl;
r = ctx->Execute();
cout << "---" << endl;
asIScriptFunction* func2 = engine->GetModule(0)->GetFunctionByDecl("int main()");
if (func2 == 0)
cout << "The function 'main' was not found." << endl;
ctx->Release();
engine->Release();
return -1;
r = ctx->Prepare(func2);
r = ctx->Execute();
if( r != asEXECUTION_FINISHED )
// The execution didn't finish as we had planned. Determine why.
if( r == asEXECUTION_ABORTED )
cout << "The script was aborted before it could finish. Probably it timed out." << endl;
else if( r == asEXECUTION_EXCEPTION )
cout << "The script ended with an exception." << endl;
// Write some information about the script exception
asIScriptFunction *func = ctx->GetExceptionFunction();
cout 手机脚本一般用啥写
是否可以使用 LLVM IR 作为通用语言在编程语言之间进行转换?