接上篇博文 NDK下 将Platinum SDK 编译成so库 (android - upnp)

讲述了如何利用该代码库编译给android程序调用的so库,其中也提到了,在使用sample-upnp工程来测试生成的so库是无效的

大家比对一下Platinum开发库的Platinum\Source\Platform\Android\module\platinum\jni\platinum-jni.cpp和

Platinum\Source\Tests\MediaRenderer\MediaRendererTest.cpp

platinum-jni.cpp

  1. #include <assert.h>
  2. #include <jni.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5.  
  6. #include "platinum-jni.h"
  7. #include "Platinum.h"
  8.  
  9. #include <android/log.h>
  10.  
  11. /*----------------------------------------------------------------------
  12. | logging
  13. +---------------------------------------------------------------------*/
  14. NPT_SET_LOCAL_LOGGER("platinum.android.jni")
  15.  
  16. /*----------------------------------------------------------------------
  17. | functions
  18. +---------------------------------------------------------------------*/
  19. __attribute__((constructor)) static void onDlOpen(void)
  20. {
  21. }
  22.  
  23. /*----------------------------------------------------------------------
  24. | JNI_OnLoad
  25. +---------------------------------------------------------------------*/
  26. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
  27. {
  28. NPT_LogManager::GetDefault().Configure("plist:.level=FINE;.handlers=ConsoleHandler;.ConsoleHandler.outputs=2;.ConsoleHandler.colors=false;.ConsoleHandler.filter=59");
  29. return JNI_VERSION_1_4;
  30. }
  31.  
  32. /*
  33. * Class: com_plutinosoft_platinum_UPnP
  34. * Method: _init
  35. * Signature: ()J
  36. */
  37. JNIEXPORT jlong JNICALL Java_com_plutinosoft_platinum_UPnP__1init(JNIEnv *env, jclass)
  38. {
  39. NPT_LOG_INFO("init");
  40. PLT_UPnP* self = new PLT_UPnP();
  41. return (jlong)self;
  42. }
  43.  
  44. /*
  45. * Class: com_plutinosoft_platinum_UPnP
  46. * Method: _start
  47. * Signature: (J)I
  48. */
  49. JNIEXPORT jint JNICALL Java_com_plutinosoft_platinum_UPnP__1start(JNIEnv *, jclass, jlong _self)
  50. {
  51. NPT_LOG_INFO("start");
  52. PLT_UPnP* self = (PLT_UPnP*)_self;
  53.  
  54. return self->Start();
  55. }
  56.  
  57. /*
  58. * Class: com_plutinosoft_platinum_UPnP
  59. * Method: _stop
  60. * Signature: (J)I
  61. */
  62. JNIEXPORT jint JNICALL Java_com_plutinosoft_platinum_UPnP__1stop(JNIEnv *, jclass, jlong _self)
  63. {
  64. NPT_LOG_INFO("stop");
  65. PLT_UPnP* self = (PLT_UPnP*)_self;
  66.  
  67. return self->Stop();
  68. }

MediaRendererTest.cpp

  1. #include "PltUPnP.h"
  2. #include "PltMediaRenderer.h"
  3.  
  4. #include <stdlib.h>
  5.  
  6. /*----------------------------------------------------------------------
  7. | globals
  8. +---------------------------------------------------------------------*/
  9. struct Options {
  10. const char* friendly_name;
  11. } Options;
  12.  
  13. /*----------------------------------------------------------------------
  14. | PrintUsageAndExit
  15. +---------------------------------------------------------------------*/
  16. static void
  17. PrintUsageAndExit(char** args)
  18. {
  19. fprintf(stderr, "usage: %s [-f <friendly_name>]\n", args[0]);
  20. fprintf(stderr, "-f : optional upnp server friendly name\n");
  21. fprintf(stderr, "<path> : local path to serve\n");
  22. exit(1);
  23. }
  24.  
  25. /*----------------------------------------------------------------------
  26. | ParseCommandLine
  27. +---------------------------------------------------------------------*/
  28. static void
  29. ParseCommandLine(char** args)
  30. {
  31. const char* arg;
  32. char** tmp = args+1;
  33.  
  34. /* default values */
  35. Options.friendly_name = NULL;
  36.  
  37. while ((arg = *tmp++)) {
  38. if (!strcmp(arg, "-f")) {
  39. Options.friendly_name = *tmp++;
  40. } else {
  41. fprintf(stderr, "ERROR: too many arguments\n");
  42. PrintUsageAndExit(args);
  43. }
  44. }
  45. }
  46.  
  47. /*----------------------------------------------------------------------
  48. | main
  49. +---------------------------------------------------------------------*/
  50. int
  51. main(int /* argc */, char** argv)
  52. {
  53. PLT_UPnP upnp;
  54.  
  55. /* parse command line */
  56. ParseCommandLine(argv);
  57.  
  58. PLT_DeviceHostReference device(
  59. new PLT_MediaRenderer(Options.friendly_name?Options.friendly_name:"Platinum Media Renderer",
  60. false,
  61. "e6572b54-f3c7-2d91-2fb5-b757f2537e21"));
  62. upnp.AddDevice(device);
  63. bool added = true;
  64.  
  65. upnp.Start();
  66.  
  67. char buf[256];
  68. while (gets(buf)) {
  69. if (*buf == 'q')
  70. break;
  71.  
  72. if (*buf == 's') {
  73. if (added) {
  74. upnp.RemoveDevice(device);
  75. } else {
  76. upnp.AddDevice(device);
  77. }
  78. added = !added;
  79. }
  80. }
  81.  
  82. upnp.Stop();
  83. return 0;
  84. }

可以看出JNI接口中的PLT_UPnP对象并没有加入PLT_DeviceHostReference对象,所以无法启动设备,只要参照MediaRenderTest.cpp的做法我们就可以实现一个dmr设备的开启与关闭了,童鞋们可以仿照博文 基于Platinum库的DMR实现(android)当中的jni类来尝试实现一下这两个接口

public static native int startMediaRender(byte[] friendname ,byte[] uuid);

public static native int stopMediaRender();

完成这一步,DMR的实现就已经成功一半了

接下来我们要做的两件事就是

1.将外部的action事件通过反射机制抛给java层处理

2.通过jni将一些事件状态值更新至所在服务列表

先看第一点,每当有action事件到来时,PLT_MediaRenderer的

virtual NPT_Result OnAction(PLT_ActionReference&action,const PLT_HttpRequestContext& context);方法就会被调用

  1. NPT_Result
  2. PLT_MediaRenderer::OnAction(PLT_ActionReference& action,
  3. const PLT_HttpRequestContext& context)
  4. {
  5. NPT_COMPILER_UNUSED(context);
  6.  
  7. /* parse the action name */
  8. NPT_String name = action->GetActionDesc().GetName();
  9.  
  10. // since all actions take an instance ID and we only support 1 instance
  11. // verify that the Instance ID is 0 and return an error here now if not
  12. NPT_String serviceType = action->GetActionDesc().GetService()->GetServiceType();
  13. if (serviceType.Compare("urn:schemas-upnp-org:service:AVTransport:1", true) == 0) {
  14. if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) {
  15. action->SetError(718, "Not valid InstanceID");
  16. return NPT_FAILURE;
  17. }
  18. }
  19. serviceType = action->GetActionDesc().GetService()->GetServiceType();
  20. if (serviceType.Compare("urn:schemas-upnp-org:service:RenderingControl:1", true) == 0) {
  21. if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) {
  22. action->SetError(702, "Not valid InstanceID");
  23. return NPT_FAILURE;
  24. }
  25. }
  26.  
  27. /* Is it a ConnectionManager Service Action ? */
  28. if (name.Compare("GetCurrentConnectionInfo", true) == 0) {
  29. return OnGetCurrentConnectionInfo(action);
  30. }
  31.  
  32. /* Is it a AVTransport Service Action ? */
  33. if (name.Compare("Next", true) == 0) {
  34. return OnNext(action);
  35. }
  36. if (name.Compare("Pause", true) == 0) {
  37. return OnPause(action);
  38. }
  39. if (name.Compare("Play", true) == 0) {
  40. return OnPlay(action);
  41. }
  42. if (name.Compare("Previous", true) == 0) {
  43. return OnPrevious(action);
  44. }
  45. if (name.Compare("Seek", true) == 0) {
  46. return OnSeek(action);
  47. }
  48. if (name.Compare("Stop", true) == 0) {
  49. return OnStop(action);
  50. }
  51. if (name.Compare("SetAVTransportURI", true) == 0) {
  52. return OnSetAVTransportURI(action);
  53. }
  54. if (name.Compare("SetPlayMode", true) == 0) {
  55. return OnSetPlayMode(action);
  56. }
  57.  
  58. /* Is it a RendererControl Service Action ? */
  59. if (name.Compare("SetVolume", true) == 0) {
  60. return OnSetVolume(action);
  61. }
  62. if (name.Compare("SetVolumeDB", true) == 0) {
  63. return OnSetVolumeDB(action);
  64. }
  65. if (name.Compare("GetVolumeDBRange", true) == 0) {
  66. return OnGetVolumeDBRange(action);
  67.  
  68. }
  69. if (name.Compare("SetMute", true) == 0) {
  70. return OnSetMute(action);
  71. }
  72.  
  73. // other actions rely on state variables
  74. NPT_CHECK_LABEL_WARNING(action->SetArgumentsOutFromStateVariable(), failure);
  75. return NPT_SUCCESS;
  76.  
  77. failure:
  78. action->SetError(401,"No Such Action.");
  79. return NPT_FAILURE;
  80. }

部分事件会由m_Delegate成员变量来处理,也就是 virtual void SetDelegate(PLT_MediaRendererDelegate* delegate) { m_Delegate = delegate; }传进来的

所以我们只需要从PLT_MediaRendererDelegate类派生一个子类,然后将它设进PLT_MediaRenderer并实现相应的action方法并把一些需要的值反射出来即可

  1. class PLT_MediaRendererDelegate
  2. {
  3. public:
  4. virtual ~PLT_MediaRendererDelegate() {}
  5.  
  6. // ConnectionManager
  7. virtual NPT_Result OnGetCurrentConnectionInfo(PLT_ActionReference& action) = 0;
  8.  
  9. // AVTransport
  10. virtual NPT_Result OnNext(PLT_ActionReference& action) = 0;
  11. virtual NPT_Result OnPause(PLT_ActionReference& action) = 0;
  12. virtual NPT_Result OnPlay(PLT_ActionReference& action) = 0;
  13. virtual NPT_Result OnPrevious(PLT_ActionReference& action) = 0;
  14. virtual NPT_Result OnSeek(PLT_ActionReference& action) = 0;
  15. virtual NPT_Result OnStop(PLT_ActionReference& action) = 0;
  16. virtual NPT_Result OnSetAVTransportURI(PLT_ActionReference& action) = 0;
  17. virtual NPT_Result OnSetPlayMode(PLT_ActionReference& action) = 0;
  18.  
  19. // RenderingControl
  20. virtual NPT_Result OnSetVolume(PLT_ActionReference& action) = 0;
  21. virtual NPT_Result OnSetVolumeDB(PLT_ActionReference& action) = 0;
  22. virtual NPT_Result OnGetVolumeDBRange(PLT_ActionReference& action) = 0;
  23. virtual NPT_Result OnSetMute(PLT_ActionReference& action) = 0;
  24. };
  1. void ActionInflect(int cmd, const char* value, const char* data)
  2. {
  3.  
  4. if (g_vm == NULL)
  5. {
  6. UpnpPrintInfo("g_vm = NULL!!!");
  7. return ;
  8. }
  9.  
  10. int status;
  11. JNIEnv *env = NULL;
  12. bool isAttach = false;
  13. status = g_vm->GetEnv((void **) &env, JNI_VERSION_1_6);
  14. if(status != JNI_OK)
  15. {
  16. status = g_vm->AttachCurrentThread(&env, NULL);
  17. if(status < 0) {
  18. UpnpPrintInfo("callback_handler: failed to attach , current thread, status = %d", status);
  19. return;
  20. }
  21. isAttach = true;
  22. }
  23.  
  24. jstring valueString = NULL;
  25. jstring dataString = NULL;
  26. jclass inflectClass = g_inflectClass;
  27. jmethodID inflectMethod = g_methodID;
  28.  
  29. if (inflectClass == NULL || inflectMethod == NULL)
  30. {
  31. goto end;
  32. }
  33.  
  34. // UpnpPrintInfo("CMD = %d\nVALUE = %s\nDATA = %s",cmd, value, data);
  35.  
  36. valueString = env->NewStringUTF(value);
  37. dataString = env->NewStringUTF(data);
  38.  
  39. env->CallStaticVoidMethod(inflectClass, inflectMethod, cmd, valueString, dataString);
  40.  
  41. env->DeleteLocalRef(valueString);
  42. env->DeleteLocalRef(dataString);
  43.  
  44. end:
  45. if (env->ExceptionOccurred())
  46. {
  47. env->ExceptionDescribe();
  48. env->ExceptionClear();
  49. }
  50. if (isAttach)
  51. {
  52. g_vm->DetachCurrentThread();
  53. }
  54.  
  55. }

再看第二点,如何将事件变量值更新至服务列表

首先通过FindServiceByType方法找到urn:schemas-upnp-org:service:AVTransport:1服务,

然后通过SetStateVariable更新值即可

变量名与值对应关系大家参照dlna文档开发即可

http://download.csdn.net/detail/geniuseoe2012/4969961

重点看standardizeddcps\MediaServer_4 and  MediaRenderer_3下的UPnP-av-AVTransport-v3-Service-20101231.pdf文档

代码实现可以参照PLT_MediaRenderer::SetupServices()方法

  1. NPT_Result
  2. PLT_MediaRenderer::SetupServices()
  3. {
  4. PLT_Service* service;
  5.  
  6. {
  7. /* AVTransport */
  8. service = new PLT_Service(
  9. this,
  10. "urn:schemas-upnp-org:service:AVTransport:1",
  11. "urn:upnp-org:serviceId:AVTransport",
  12. "AVTransport",
  13. "urn:schemas-upnp-org:metadata-1-0/AVT/");
  14. NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_AVTransportSCPD));
  15. NPT_CHECK_FATAL(AddService(service));
  16.  
  17. service->SetStateVariableRate("LastChange", NPT_TimeInterval(0.2f));
  18. service->SetStateVariable("A_ARG_TYPE_InstanceID", "0");
  19.  
  20. // GetCurrentTransportActions
  21. service->SetStateVariable("CurrentTransportActions", "Play,Pause,Stop,Seek,Next,Previous");
  22.  
  23. // GetDeviceCapabilities
  24. service->SetStateVariable("PossiblePlaybackStorageMedia", "NONE,NETWORK,HDD,CD-DA,UNKNOWN");
  25. service->SetStateVariable("PossibleRecordStorageMedia", "NOT_IMPLEMENTED");
  26. service->SetStateVariable("PossibleRecordQualityModes", "NOT_IMPLEMENTED");
  27.  
  28. // GetMediaInfo
  29. service->SetStateVariable("NumberOfTracks", "0");
  30. service->SetStateVariable("CurrentMediaDuration", "00:00:00");
  31. service->SetStateVariable("AVTransportURI", "");
  32. service->SetStateVariable("AVTransportURIMetadata", "");;
  33. service->SetStateVariable("NextAVTransportURI", "NOT_IMPLEMENTED");
  34. service->SetStateVariable("NextAVTransportURIMetadata", "NOT_IMPLEMENTED");
  35. service->SetStateVariable("PlaybackStorageMedium", "NONE");
  36. service->SetStateVariable("RecordStorageMedium", "NOT_IMPLEMENTED");
  37. service->SetStateVariable("RecordMediumWriteStatus", "NOT_IMPLEMENTED");
  38.  
  39. // GetPositionInfo
  40. service->SetStateVariable("CurrentTrack", "0");
  41. NPT_Result durResult = service->SetStateVariable("CurrentTrackDuration", "00:00:00");
  42. service->SetStateVariable("CurrentTrackMetadata", "");
  43. service->SetStateVariable("CurrentTrackURI", "");
  44. NPT_Result relTimeResult = service->SetStateVariable("RelativeTimePosition", "00:00:00");
  45. service->SetStateVariable("AbsoluteTimePosition", "00:50:00");
  46. service->SetStateVariable("RelativeCounterPosition", "2147483647"); // means NOT_IMPLEMENTED
  47. service->SetStateVariable("AbsoluteCounterPosition", "2147483647"); // means NOT_IMPLEMENTED
  48.  
  49. // disable indirect eventing for certain state variables
  50. PLT_StateVariable* var;
  51. var = service->FindStateVariable("RelativeTimePosition");
  52. if (var) var->DisableIndirectEventing();
  53. var = service->FindStateVariable("AbsoluteTimePosition");
  54. if (var) var->DisableIndirectEventing();
  55. var = service->FindStateVariable("RelativeCounterPosition");
  56. if (var) var->DisableIndirectEventing();
  57. var = service->FindStateVariable("AbsoluteCounterPosition");
  58. if (var) var->DisableIndirectEventing();
  59.  
  60. // GetTransportInfo
  61. service->SetStateVariable("TransportState", "NO_MEDIA_PRESENT");
  62. service->SetStateVariable("TransportStatus", "OK");
  63. service->SetStateVariable("TransportPlaySpeed", "1");
  64.  
  65. // GetTransportSettings
  66. service->SetStateVariable("CurrentPlayMode", "NORMAL");
  67. service->SetStateVariable("CurrentRecordQualityMode", "NOT_IMPLEMENTED");
  68. }
  69.  
  70. {
  71. /* ConnectionManager */
  72. service = new PLT_Service(
  73. this,
  74. "urn:schemas-upnp-org:service:ConnectionManager:1",
  75. "urn:upnp-org:serviceId:ConnectionManager",
  76. "ConnectionManager");
  77. NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_ConnectionManagerSCPD));
  78. NPT_CHECK_FATAL(AddService(service));
  79.  
  80. service->SetStateVariable("CurrentConnectionIDs", "0");
  81.  
  82. // put all supported mime types here instead
  83. service->SetStateVariable("SinkProtocolInfo", "http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_SP_G726,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMDRM_WMABASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPLL_BASE,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC_XAC3,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMDRM_WMVSPLL_BASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_BASE,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_ASP_L5_SO_G726,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL_XAC3,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAPRO,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_ASP_L4_SO_G726,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3X,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_MP3,http-get:*:video/x-ms-wmv:*,http-get:*:video/mp4:*");
  84. service->SetStateVariable("SourceProtocolInfo", "");
  85. }
  86.  
  87. {
  88. /* RenderingControl */
  89. service = new PLT_Service(
  90. this,
  91. "urn:schemas-upnp-org:service:RenderingControl:1",
  92. "urn:upnp-org:serviceId:RenderingControl",
  93. "RenderingControl",
  94. "urn:schemas-upnp-org:metadata-1-0/RCS/");
  95. NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_RenderingControlSCPD));
  96. NPT_CHECK_FATAL(AddService(service));
  97.  
  98. service->SetStateVariableRate("LastChange", NPT_TimeInterval(0.2f));
  99.  
  100. service->SetStateVariable("Mute", "0");
  101. service->SetStateVariableExtraAttribute("Mute", "Channel", "Master");
  102. service->SetStateVariable("Volume", "100");
  103. service->SetStateVariableExtraAttribute("Volume", "Channel", "Master");
  104. service->SetStateVariable("VolumeDB", "0");
  105. service->SetStateVariableExtraAttribute("VolumeDB", "Channel", "Master");
  106.  
  107. service->SetStateVariable("PresetNameList", "FactoryDefaults");
  108. }
  109.  
  110. return NPT_SUCCESS;
  111. }

至此代码实现步骤已全部讲解完毕,当然在具体实现过程中多多少少会遇到些问题

根据log信息多问问谷哥度娘,一般都能找到解决方案的

同时在jni层转换C++类型与java类型时一定要注意及时释放资源,不要造成内存泄漏了

另外不要再向楼主索要源码了,编程最重要的是思维

只有自己动手实践了,摸索了,思考了,解决了,自身水平才会提高

否则你永远都只能是code-farmer而无法成为code-designer

授之以鱼不如授之予渔也是蓝老师一贯的教学宗旨,伸手党请自觉绕道

最后感谢大家的支持,我们下节课再见!

more brilliant,Please pay attention to my CSDN blog -->http://blog.csdn.net/geniuseoe2012

关于Platinum库的MediaRender具体C++代码实现探讨的更多相关文章

  1. 基于Platinum库的DMS实现(android)

    接上篇博文:基于Platinum库的DMR实现(android) 文章讲述了如何使用Platinum库实现DMR 今天同样使用该库,来讲解一下DMS的实现 关于该库如何编译,请参考这篇博文:NDK下 ...

  2. [转]如何利用ndk-stack工具查看so库的调用堆栈【代码示例】?

    如何利用ndk-stack工具查看so库的调用堆栈[代码示例]? http://hi.baidu.com/subo4110/item/d00395b3bf63e4432bebe36d Step1:An ...

  3. 在Team Foundation Server (TFS)的代码库或配置库中查找文件或代码

    [update 2017.2.11] 最新版本的TFS 2017已经增加了代码搜索功能,可以参考这个链接 https://blogs.msdn.microsoft.com/visualstudioal ...

  4. php spl标准库简介(SPL是Standard PHP Library(PHP标准库)(直接看代码实例,特别方便)

    php spl标准库简介(SPL是Standard PHP Library(PHP标准库)(直接看代码实例,特别方便) 一.总结 直接看代码实例,特别方便易懂 thinkphp控制器利眠宁不支持(说明 ...

  5. JavaScript公共库event-stream被植入恶意代码

    [安全预警]JavaScript公共库event-stream被植入恶意代码 2018年11月27日,阿里云云盾应急响应中心监测到JavaScript公共库event-stream被植入恶意代码,该恶 ...

  6. AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码

    目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...

  7. jstl标签库基础教程及其使用代码

    概述 在 JSP 页面中,使用标签库代替传统的 Java 片段语言来实现页面的显示逻辑已经不是新技术了,然而,由自定义标签很容易造成重复定义和非标准的实现.鉴于此,出现了 JSTL ( JSP Sta ...

  8. MVP模式, 开源库mosby的使用及代码分析

    Android中的构架模式一直是一个很hot的topic, 近年来Architecture components推出之后, MVVM异军突起, 风头正在逐渐盖过之前的MVP. 其实我觉得MVP还是有好 ...

  9. x64共享库中的位置无关代码(PIC)

    原作者:Eli Bendersky http://eli.thegreenplace.net/2011/11/11/position-independent-code-pic-in-shared-li ...

随机推荐

  1. 单击Android设备后退键,主屏幕键以及旋转屏幕如何影响Activity的生命周期

    单击设备的后退键,相当于通知Android系统“我已完成activity的使用,现在不需要它了.”接到指令后,系统立即销毁了activity.即调用onPause()->onStop()-> ...

  2. Linux 静态库&动态库调用

    1.什么是库在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.由于windows和linux的本质不同,因此二者库的二进制是不 ...

  3. 1.0.x-学习Opencv与MFC混合编程之---视频运动检测

    源代码地址: http://download.csdn.net/detail/nuptboyzhb/3961668 版本1.0.x新增内容 视频运动检测 Ø 新建菜单项,Learning OpenCV ...

  4. View实现涂鸦、撤销以及重做功能

    import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import j ...

  5. .net面试题大全(有答案)

    在网上找来的,希望对大家有所帮助.     1 (1)面向对象的语言具有__继承性_性._封装性_性._多态性 性. (2)能用foreach遍历访问的对象需要实现 _ IEnumerable 接口或 ...

  6. 有没有安全的工作?(99条评论)——结论是没有一劳永逸的工作,要终身学习,IT业刚出道和老手还是有区别的(同样对于新技术,薪资可能是个问题)

    作者: 阮一峰 日期: 2015年12月15日 如果你经常使用互联网,可能知道有一种东西叫做Flash. 它是一种软件,用来制作网页游戏.动画,以及视频播放器.只要观看网络视频,基本都会用到它. 七八 ...

  7. C2B未来:大数据定制

    昨天看到微信SuperSofter写了一篇文章,有感而发.以便备记. 这是一种典型的C2B模式.阿里不仅仅是在与腾讯拼移动.它的电商本土业务也在稳步推进.近期一个里程碑事件是.阿里包下了美的.九阳.苏 ...

  8. 函数alv下的颜色设置

    ABAP中的颜色代码是由4位字都组成的 cxyz    c:color的简写,颜色代码均以C开头 x:标准色代码,SAP中一共有7个标准色    y:反转颜色启用/关闭 1/0 z:增强颜色启用/关闭 ...

  9. 【Demo 0006】iOS常用控件

    本章学习要点       1.  了解iOS中控件继承关系:       2.  掌握UIControl基础知识;       3.  掌握UIButton基本用法:       4.  掌握UILa ...

  10. UVA 116 Unidirectional TSP(dp + 数塔问题)

     Unidirectional TSP  Background Problems that require minimum paths through some domain appear in ma ...