使用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 作为通用语言在编程语言之间进行转换?

将 PostgreSQL SQL 转储转换为 PostgreSQL 自定义格式转储

C语言中如何将二维字符数组作为函数参数引用传递

Scala 中apply方法的用法

以太坊白皮书解析