如何使用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 nb_streams);
for (int i = 0; i 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) 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(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 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 // cout
#include // assert()
#include // strstr()
#ifdef __linux__
#include
#include
#include
#include
#else
#include // kbhit(), getch()
#include // timeGetTime()
#endif
#include
#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 message);
}
int RunApplication()
{
int r;
// Create the script engine
asIScriptEngine *engine = asCreateScriptEngine();
if( engine == 0 )
{
cout
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?