[{"data":1,"prerenderedAt":343},["ShallowReactive",2],{"page-插件-1":3,"page-count-插件":342},[4],{"id":5,"title":6,"body":7,"date":317,"description":13,"extension":318,"meta":319,"navigation":322,"path":334,"seo":335,"stem":336,"tags":337,"__hash__":341},"blogs\u002F_legacy\u002F2015\u002F2015-09-10-ue4-taglib-usage-and-plugin.md","UE4中Taglib使用及插件制作",{"type":8,"value":9,"toc":307},"minimark",[10,14,17,22,25,28,39,42,48,51,55,58,61,72,75,78,81,85,88,94,97,100,106,109,115,118,121,126,129,135,138,141,146,149,155,158,163,166,171,174,177,181,184,187,196,199,202,208,212,215,218,221,227,230,236,239,245,248,259,266,269,272,278,281,287,290,296,299],[11,12,13],"p",{},"UE4使用第三方库时，为了方便跨平台编译、避免冲突和多次复用，将其制作成插件是不错的选择。",[11,15,16],{},"当前UE4版本为4.10.1。",[18,19,21],"h2",{"id":20},"taglib的使用","Taglib的使用",[11,23,24],{},"Taglib是一个用于读取多媒体文件标签的第三方库，之所以会使用到，是因为当前FMod在读取含有非英文的标签会得到错误的结果。",[11,26,27],{},"Taglib需要自己使用CMake进行配置和编译。如果只是在Windows下使用的话，最简单的方法是直接引用生成的.lib文件。在项目的.build.cs中，ModuleRules的实现里面添加：",[29,30,35],"pre",{"className":31,"code":33,"language":34},[32],"language-text","PublicIncludePaths.Add(\"F:\u002FLibs\u002Ftaglib-master\u002Finclude\u002Ftaglib\");\n\nPublicAdditionalLibraries.Add(\"F:\u002FLibs\u002Ftaglib-master\u002Ftaglib\u002FRelease\u002Ftag.lib\");\n","text",[36,37,33],"code",{"__ignoreMap":38},"",[11,40,41],{},"然后在需要使用的地方使用Taglib即可",[29,43,46],{"className":44,"code":45,"language":34},[32],"#define TAGLIB_STATIC\n\n#include \"fileref.h\"\n\n#include \"tag.h\"\n\n#include \"tpropertymap.h\"\n\n\u002F\u002F ……\n\n\u002F** TagLib Fetch Tag *\u002F\n\nMusicItem->AlubmName = \"\";\n\nMusicItem->ArtistName = \"\";\n\nTagLib::FileRef TLFile(*MusicFullPath);\n\nif (!TLFile.isNull() && TLFile.tag()){\n\n    OutputDebugStringA(\"TagLib Fetch Reading Begin.\\n\");\n\n    TagLib::Tag *tag = TLFile.tag();\n\n    std::wstring tWsName = tag->title().toWString();\n\n    if (tWsName.length()>0)    MusicItem->SetDisplayName(tWsName.c_str());\n\n    MusicItem->AlubmName = tag->album().toWString().c_str();\n\n    MusicItem->ArtistName = tag->artist().toWString().c_str();\n\n}\n\nelse{\n\n    OutputDebugStringA(\"TagLib Fetch Fails.\\n\");\n\n}\n\n\u002F** TagLib Fetch Tag - End *\u002F\n",[36,47,45],{"__ignoreMap":38},[11,49,50],{},"但是这样的方法在进行Android之类的平台上的编译时，会遇到很多麻烦。因此将其制作为UE4插件是最好的解决方法。",[18,52,54],{"id":53},"ue4插件制作","UE4插件制作",[11,56,57],{},"UE4的插件制作一直都处在WIP的状态，直到4.9版本开始，官方文档才变更为了可以使用的状态。因此，为了避免研究了之后官方大规模的更新，到了现在才开始研究。",[11,59,60],{},"UE4插件的制作相对还是比较简单的，在引擎中，官方就已经提供了4个示例插件，以其为基础进行插件开发即可。",[11,62,63,64,71],{},"插件的代码布局和UE4的游戏项目差不多，只有在Public中定义的类对外界才是可见的。详细的插件系统介绍可以参照[",[65,66,70],"a",{"href":67,"rel":68},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FProgramming\u002FPlugins\u002F",[69],"nofollow","官方文档","]。",[11,73,74],{},"插件的描述文件中最重要的地方是Modules中的Type参数，这个参数是决定插件的加载类型的。通常情况下，如果是在实际游戏逻辑中使用的插件的话，这里需要修改为Runtime。",[11,76,77],{},"如果是在项目的Plugins目录中添加插件目录进行开发的话，需要重新生成下项目文件",[11,79,80],{},"这样才能在vs中看到插件。还有比较容易忘记的是，直接继承自UObject的类，必须定义Blueprintable才可以在编辑器中可见。",[18,82,84],{"id":83},"taglib改造","Taglib改造",[11,86,87],{},"将taglib的源代码整个扔到Private目录中去，并在.build.cs中添加包含路径",[29,89,92],{"className":90,"code":91,"language":34},[32],"            PrivateIncludePaths.AddRange(\n\n                new string[] {\n\n                    \"TagLibs\u002FPrivate\",\"TagLibs\u002FPrivate\u002Ftaglib\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Ftoolkit\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fasf\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fmpeg\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fogg\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fogg\u002Fflac\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fflac\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fmpc\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fmp4\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fogg\u002Fvorbis\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fogg\u002Fspeex\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fogg\u002Fopus\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fmpeg\u002Fid3v2\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fmpeg\u002Fid3v2\u002Fframes\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fmpeg\u002Fid3v1\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fape\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fwavpack\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Ftrueaudio\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Friff\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Friff\u002Faiff\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Friff\u002Fwav\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fmod\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fs3m\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fit\", \"TagLibs\u002FPrivate\u002Ftaglib\u002Fxm\"\n\n                }\n\n                );\n",[36,93,91],{"__ignoreMap":38},[11,95,96],{},"要添加的比较多，主要是因为Taglib本身使用的就是这样的方法，稍微有点麻烦。",[11,98,99],{},"添加完路径之后，首先遇到的错误是",[101,102,103],"blockquote",{},[11,104,105],{},"2>EXEC : error : The first include statement in source file ‘F:\\Unreal\\PluginDev\\Plugins\\TagLibs\\Source\\TagLibs\\Private\\taglib\\mpeg\\id3v2\\id3v2header.cpp’ is trying to include the file ‘iostream’ as the precompiled header, but that file could not be located in any of the module’s include search paths.",[11,107,108],{},"这个错误的来源乍看之下很奇怪，其实在项目中有时候也会遇到。修正方法是，在cpp文件中首先包含模块头文件。",[29,110,113],{"className":111,"code":112,"language":34},[32],"#include \"TagLibsPrivatePCH.h\"\n",[36,114,112],{"__ignoreMap":38},[11,116,117],{},"添加了上面的文件之后，就会遇到Taglib内部大规模的namespace引发的错误，这一部分只能是一个一个的对命名空间进行控制修改了。",[11,119,120],{},"命名空间修正之后，会遇到如下错误",[101,122,123],{},[11,124,125],{},"error C2872: “DWORD”: 不明确的符号",[11,127,128],{},"在UE4内部有对DWORD进行禁止使用的机制，这里需要重新开启。开启的方法是使用UE4内部提供的机制。",[29,130,133],{"className":131,"code":132,"language":34},[32],"#include \"AllowWindowsPlatformTypes.h\"\n\n#include \u003Cwindows.h>\n\n#include \"HideWindowsPlatformTypes.h\"\n",[36,134,132],{"__ignoreMap":38},[11,136,137],{},"这样的话就可以使用DWORD等了。",[11,139,140],{},"在编译过程中还会遇到",[101,142,143],{},[11,144,145],{},"4310:编译器执行的转换将截断数据",[11,147,148],{},"这个错误出现点有点多，直接让编译器忽略比较快。",[29,150,153],{"className":151,"code":152,"language":34},[32],"#pragma warning(disable: 4310)\n",[36,154,152],{"__ignoreMap":38},[11,156,157],{},"经过上面的几个步骤，基本就可以正常的通过编译了。只是在打包的时候会有这样的错误：",[101,159,160],{},[11,161,162],{},"UnrealBuildTool: ERROR: Couldn’t find referenced module ‘PluginName’",[11,164,165],{},"或者",[101,167,168],{},[11,169,170],{},"Plugin ‘PluginName’ failed to load because module ‘PluginName’ could not be found. Please ensure the plugin is properly installed, otherwise consider disabling the plugin for this project",[11,172,173],{},"这时候需要在Development下对代码进行一次重新编译。",[11,175,176],{},"这样的话就可以在Windows下正常的使用了。",[18,178,180],{"id":179},"android平台","Android平台",[11,182,183],{},"插件在Android平台打包时会遇到很多编译器相关的错误，需要进行一些修正。",[11,185,186],{},"首先遇到的错误是",[101,188,189],{},[11,190,191,192],{},"error : delete called on ‘const TagLib::FileRef::FileTypeResolver’ that is abstract but has non-virtual destructor ",[193,194,195],"span",{},"-Werror,-Wdelete-non-virtual-dtor",[11,197,198],{},"这个错误原本是warning，据说是taglib为了保证其自身的向下兼容性等原因而遗留的。",[11,200,201],{},"因此，修正方法是让编译器忽略这个warning。直接在模块头文件上加上",[29,203,206],{"className":204,"code":205,"language":34},[32],"#if defined(__clang__)\n\n#pragma clang diagnostic ignored \"-Wdocumentation\"\n\n#pragma clang diagnostic ignored \"-Wshadow\"\n\n#pragma clang diagnostic ignored \"-Wdelete-non-virtual-dtor\"\n\n#pragma clang diagnostic ignored \"-Wunused-function\"\n\n#define HAVE_SNPRINTF\n\n#endif\n",[36,207,205],{"__ignoreMap":38},[18,209,211],{"id":210},"rtti","RTTI",[11,213,214],{},"整个改造过程最麻烦的问题出在了RTTI上，Taglib内部大量的使用了dynamic_cast进行类型检测，而不是使用virtual来进行函数重载。",[11,216,217],{},"而UE4和大多数游戏引擎一样，出于效率原因是禁止使用RTTI的，好在UE4提供了可以单独在插件和项目中打开RTTI的方法。",[11,219,220],{},"在插件的.build.cs中添加如下所示的代码即可：",[29,222,225],{"className":223,"code":224,"language":34},[32],"namespace UnrealBuildTool.Rules\n\n{\n\n    public class TagLibs : ModuleRules\n\n    {\n\n        public TagLibs(TargetInfo Target)\n\n        {\n\n            bUseRTTI = true; \u002F\u002F 打开RTTI\n\n            \u002F\u002F ... ...\n",[36,226,224],{"__ignoreMap":38},[11,228,229],{},"但是，这个开关对Android是没有作用的，我们需要编辑引擎源码进行修正。在AndroidToolChain.cs中，将所有的",[29,231,234],{"className":232,"code":233,"language":34},[32],"Result += \" -fno-rtti\";\n",[36,235,233],{"__ignoreMap":38},[11,237,238],{},"改为",[29,240,243],{"className":241,"code":242,"language":34},[32],"if (!CompileEnvironment.Config.bUseRTTI) Result += \" -fno-rtti\";\n",[36,244,242],{"__ignoreMap":38},[11,246,247],{},"混合使用RTTI的情况下需要注意的是，根据编译器的不同，将定义了virtual的多态类型在两种不同的编译方式之间混合使用时，其结果是不可预知的。具体而言可能会出现类似下面的错误：",[101,249,250,253],{},[11,251,252],{},"error: undefined reference to ‘typeinfo for UObject’",[11,254,255,256],{},"error: cannot pass object of non-trivial type ‘FString’ through variadic function; call will abort at runtime ",[193,257,258],{},"-Wnon-pod-varargs",[11,260,261,262,265],{},"结论上，就是在插件中要尽量避免使用UE4内部的类。详细的技术上的原因可以参照",[193,263,264],{},"这里","。",[18,267,268],{"id":268},"插件使用",[11,270,271],{},"插件制作完成后，使用起来就比较简单了。如果要在代码中使用TagLibs插件的话，在.build.cs中添加",[29,273,276],{"className":274,"code":275,"language":34},[32],"PrivateDependencyModuleNames.AddRange(new string[] { \"TagLibs\" });\n",[36,277,275],{"__ignoreMap":38},[11,279,280],{},"然后在要使用的类，一般是蓝图函数库的文件中添加包含",[29,282,285],{"className":283,"code":284,"language":34},[32],"#include \"ITagLibs.h\"\n",[36,286,284],{"__ignoreMap":38},[11,288,289],{},"以及使用",[29,291,294],{"className":292,"code":293,"language":34},[32],"ITagLibs::Get().GetMusicInfo(args…)\n",[36,295,293],{"__ignoreMap":38},[11,297,298],{},"即可。",[11,300,301,302,71],{},"其他详情可参见完成的Taglib插件源码，已上传至[",[65,303,306],{"href":304,"rel":305},"https:\u002F\u002Fgithub.com\u002Fsteinkrausls\u002FUE4-TagLibs",[69],"Github",{"title":38,"searchDepth":308,"depth":309,"links":310},2,3,[311,312,313,314,315,316],{"id":20,"depth":308,"text":21},{"id":53,"depth":308,"text":54},{"id":83,"depth":308,"text":84},{"id":179,"depth":308,"text":180},{"id":210,"depth":308,"text":211},{"id":268,"depth":308,"text":268},"2015-09-10","md",{"layout":320,"status":321,"published":322,"author":323,"author_login":324,"author_email":325,"author_url":326,"wordpress_id":327,"wordpress_url":328,"date_gmt":329,"excerpt":330},"post","publish",true,{"display_name":324,"login":324,"email":325,"url":326},"chaoshikari","chaoshikari@gmail.com","\u002F",1482,"\u002F\u002F?p=1482","2015-09-10 12:21:07 +0000",{"type":8,"value":331},[332],[11,333,13],{},"\u002F2015-09-10-ue4-taglib-usage-and-plugin",{"title":6,"description":13},"_legacy\u002F2015\u002F2015-09-10-ue4-taglib-usage-and-plugin",[338,339,340],"UE4","Taglib","插件","V3L6gr5PK2TZukj5tZ6xm2xk6Yp5Xa77uDIKBjvTTc8",1,1788763180670]