Skip to content

Commit

Permalink
Node N-API wrapper
Browse files Browse the repository at this point in the history
Signed-off-by: Maxime Gervais <[email protected]>
  • Loading branch information
g-maxime committed Nov 12, 2018
1 parent 02081b4 commit ead85ed
Show file tree
Hide file tree
Showing 14 changed files with 2,159 additions and 2 deletions.
70 changes: 68 additions & 2 deletions Source/MediaInfoDLL/MediaInfoDLL.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,72 @@ extern "C"
return (size_t)1;
}

static size_t MediaInfoDLL_LoadFromPath(const char* Path)
{
size_t Errors = 0;

if (Module_Count > 0) {
Module_Count++;
return 1;
}

/* Load library */
#ifdef MEDIAINFO_GLIBC
MediaInfo_Module = g_module_open(Path, G_MODULE_BIND_LAZY);
#elif defined(_WIN32) || defined(WIN32)
MediaInfo_Module = LoadLibraryA(Path);
#else
MediaInfo_Module = dlopen(Path, RTLD_LAZY);
#endif
if (!MediaInfo_Module)
return (size_t) - 1;

/* Load methods */
MEDIAINFO_ASSIGN(New, "New")
MEDIAINFOLIST_ASSIGN(New, "New")
MEDIAINFO_ASSIGN(Delete, "Delete")
MEDIAINFOLIST_ASSIGN(Delete, "Delete")
MEDIAINFO_ASSIGN(Open, "Open")
MEDIAINFOLIST_ASSIGN(Open, "Open")
MEDIAINFO_ASSIGN(Open_Buffer_Init, "Open_Buffer_Init")
MEDIAINFO_ASSIGN(Open_Buffer_Continue, "Open_Buffer_Continue")
MEDIAINFO_ASSIGN(Open_Buffer_Continue_GoTo_Get, "Open_Buffer_Continue_GoTo_Get")
MEDIAINFO_ASSIGN(Open_Buffer_Finalize, "Open_Buffer_Finalize")
MEDIAINFO_ASSIGN(Open_NextPacket, "Open_NextPacket")
MEDIAINFO_ASSIGN(Close, "Close")
MEDIAINFOLIST_ASSIGN(Close, "Close")
MEDIAINFO_ASSIGN(Inform, "Inform")
MEDIAINFOLIST_ASSIGN(Inform, "Inform")
MEDIAINFO_ASSIGN(GetI, "GetI")
MEDIAINFOLIST_ASSIGN(GetI, "GetI")
MEDIAINFO_ASSIGN(Get, "Get")
MEDIAINFOLIST_ASSIGN(Get, "Get")
MEDIAINFO_ASSIGN(Output_Buffer_Get, "Output_Buffer_Get")
MEDIAINFO_ASSIGN(Output_Buffer_GetI, "Output_Buffer_GetI")
MEDIAINFO_ASSIGN(Option, "Option")
MEDIAINFOLIST_ASSIGN(Option, "Option")
MEDIAINFO_ASSIGN(State_Get, "State_Get")
MEDIAINFOLIST_ASSIGN(State_Get, "State_Get")
MEDIAINFO_ASSIGN(Count_Get, "Count_Get")
MEDIAINFOLIST_ASSIGN(Count_Get, "Count_Get")
MEDIAINFOLIST_ASSIGN(Count_Get_Files, "Count_Get_Files")
if (Errors > 0) {
// Unload DLL with errors
#ifdef MEDIAINFO_GLIBC
g_module_close(MediaInfo_Module);
#elif defined(_WIN32) || defined(WIN32)
FreeLibrary(MediaInfo_Module);
#else
dlclose(MediaInfo_Module);
#endif
MediaInfo_Module = NULL;
return (size_t) - 1;
}

Module_Count++;
return (size_t)1;
}

static size_t MediaInfoDLL_IsLoaded()
{
if (MediaInfo_Module)
Expand Down Expand Up @@ -555,7 +621,7 @@ namespace MediaInfoDLL
class MediaInfo
{
public :
MediaInfo() {if (!MediaInfo_Module) MediaInfoDLL_Load(); if (!MediaInfo_Module) {Handle = NULL; return;}; Handle = MediaInfo_New();};
MediaInfo(const char* LibraryPath=NULL) {if (!LibraryPath) MediaInfoDLL_Load(); else MediaInfoDLL_LoadFromPath(LibraryPath); if (!MediaInfo_Module) MediaInfoDLL_Load(); if (!MediaInfo_Module) {Handle = NULL; return;}; Handle = MediaInfo_New();};
~MediaInfo() {MEDIAINFO_TEST_VOID; MediaInfo_Delete(Handle);};

//File
Expand Down Expand Up @@ -590,7 +656,7 @@ namespace MediaInfoDLL
class MediaInfoList
{
public :
MediaInfoList() {MediaInfoDLL_Load(); if (!MediaInfoDLL_IsLoaded()) {Handle = NULL; return;}; Handle = MediaInfoList_New();};
MediaInfoList(const char* LibraryPath=NULL) {if (!LibraryPath) {MediaInfoDLL_Load();} else {MediaInfoDLL_LoadFromPath(LibraryPath);}; if (!MediaInfoDLL_IsLoaded()) {Handle = NULL; return;}; Handle = MediaInfoList_New();};
~MediaInfoList() {MEDIAINFO_TEST_VOID; MediaInfoList_Delete(Handle); MediaInfoDLL_UnLoad();};

//File
Expand Down
35 changes: 35 additions & 0 deletions Source/Node/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
mediainfolib
==================
Native MediaInfo library wrapper for Node.js using N-API.

Install
-------
```sh
$ npm install --save mediainfolib
```

Build
-----
```sh
npm install node-addon-api
node-gyp configure
node-gyp build
```

Usage
-----
First install the MediaInfo native library on your system (see https://mediaarea.net/MediaInfo)

```js
var mod = require('mediainfolib');
var mi = mod.MediaInfo();

mi.Open('Example.ogg');
console.log(mi.Inform());
```
See example.js for more examples.

License
-------
Use of this source code is governed by a BSD-style license.
See https://mediaarea.net/en/MediaInfo/License for more information.
124 changes: 124 additions & 0 deletions Source/Node/Source/Helpers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the License.html file in the root of the source tree.
*/

#include <locale>
#include <codecvt>

#include "Helpers.h"

//
// Helpers functions
//
bool To_Uint32(napi_env Environment, napi_value Source, uint32_t& Destination)
{ napi_valuetype Value_Type;
if (napi_typeof(Environment, Source, &Value_Type)!=napi_ok || Value_Type!=napi_number)
return false;

if (napi_get_value_uint32(Environment, Source, &Destination)!=napi_ok)
return false;

return true;
}

bool To_Int64(napi_env Environment, napi_value Source, int64_t& Destination)
{
napi_valuetype Value_Type;
if (napi_typeof(Environment, Source, &Value_Type)!=napi_ok || Value_Type!=napi_number)
return false;

if (napi_get_value_int64(Environment, Source, &Destination)!=napi_ok)
return false;

return true;
}

bool To_SizeT(napi_env Environment, napi_value Source, size_t& Destination)
{
napi_valuetype Value_Type;
if (napi_typeof(Environment, Source, &Value_Type)!=napi_ok || Value_Type!=napi_number)
return false;

switch (sizeof(size_t))
{
case 4: // size_t is 32 bits
if (napi_get_value_uint32(Environment, Source, (uint32_t*)&Destination)!=napi_ok)
return false;
break;
break;
case 8: // size_t is 64 bits
if (napi_get_value_int64(Environment, Source, (int64_t*)&Destination)!=napi_ok)
return false;
break;
default: // unsupported
napi_throw_error(Environment, NULL, "internal error: unsupported size_t size");
return false;
}

return true;
}

bool To_Unicode(napi_env Environment, napi_value Source, std::wstring& Destination)
{
napi_valuetype Value_Type;
if (napi_typeof(Environment, Source, &Value_Type)!=napi_ok || Value_Type!=napi_string)
return false;

size_t Source_Size=0;
if (napi_get_value_string_utf8(Environment, Source, NULL, 0, &Source_Size)!=napi_ok)
return false;

char Buffer[Source_Size+1];
if (napi_get_value_string_utf8(Environment, Source, (char*)Buffer, Source_Size+1, &Source_Size)!=napi_ok)
return false;

std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> Codec;
Destination=Codec.from_bytes((char*)Buffer);

return true;
}

std::string From_Unicode(std::wstring Source)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> Codec;
return Codec.to_bytes(Source);
}

napi_value From_SizeT(napi_env Environment, const size_t Source)
{
napi_value ToReturn;
switch (sizeof(size_t))
{
case 4: // size_t is 32 bits
if (napi_create_uint32(Environment, Source, &ToReturn)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_create_uint32() failed");
return Undefined(Environment); //undefined
}
break;
break;
case 8: // size_t is 64 bits
if (napi_create_int64(Environment, Source, &ToReturn)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_create_int64() failed");
return Undefined(Environment); //undefined
}
break;
default: // unsupported
napi_throw_error(Environment, NULL, "internal error: unsupported size_t size");
return Undefined(Environment); //undefined
}

return ToReturn;
}

napi_value Undefined(napi_env Environment)
{
napi_value ToReturn;
if (napi_get_undefined(Environment, &ToReturn)!=napi_ok)
napi_throw_error(Environment, NULL, "internal error: napi_get_undefined() failed, returned value may be inconsistent");

return ToReturn;
}
21 changes: 21 additions & 0 deletions Source/Node/Source/Helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the License.html file in the root of the source tree.
*/

#ifndef HelpersH
#define HelpersH

#include <string>
#include <node_api.h>

bool To_Uint32(napi_env Environment, napi_value Source, uint32_t& Destination);
bool To_Int64(napi_env Environment, napi_value Source, int64_t& Destination);
bool To_SizeT(napi_env Environment, napi_value Source, size_t& Destination);
bool To_Unicode(napi_env Environment, napi_value Source, std::wstring& Destination);
std::string From_Unicode(std::wstring Source);
napi_value From_SizeT(napi_env Environment, const size_t Source);
napi_value Undefined(napi_env Environment);

#endif //HelpersH
96 changes: 96 additions & 0 deletions Source/Node/Source/Lib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the License.html file in the root of the source tree.
*/

#include "Helpers.h"
#include "NodeMediaInfo.h"
#include "NodeMediaInfoList.h"

napi_value CreateMediaInfoObject(napi_env Environment, napi_callback_info Info)
{
size_t ArgumentsCount=1;
napi_value Arguments[ArgumentsCount];

if (napi_get_cb_info(Environment, Info, &ArgumentsCount, Arguments, NULL, NULL)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_get_cb_info() failed");
return Undefined(Environment); //undefined
}

napi_value Instance;
if (NodeMediaInfo::NewInstance(Environment, ArgumentsCount, Arguments, &Instance)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: NodeMediaInfo::NewInstance() failed");
return Undefined(Environment); //undefined
}

return Instance;
}

napi_value CreateMediaInfoListObject(napi_env Environment, napi_callback_info Info)
{
size_t ArgumentsCount=1;
napi_value Arguments[ArgumentsCount];

if (napi_get_cb_info(Environment, Info, &ArgumentsCount, Arguments, NULL, NULL)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_get_cb_info() failed");
return Undefined(Environment); //undefined
}

napi_value Instance;
if (NodeMediaInfoList::NewInstance(Environment, ArgumentsCount, Arguments, &Instance)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: NodeMediaInfoList::NewInstance() failed");
return Undefined(Environment); //undefined
}

return Instance;
}

napi_value Init(napi_env Environment, napi_value Exports)
{
if (NodeMediaInfo::Init(Environment)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: NodeMediaInfo::Init() failed");
return Undefined(Environment); //undefined
}

if (NodeMediaInfoList::Init(Environment)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: NodeMediaInfoList::Init() failed");
return Undefined(Environment); //undefined
}

napi_value MediaInfoFunc;
if (napi_create_function(Environment, "MediaInfo", NAPI_AUTO_LENGTH, CreateMediaInfoObject, NULL, &MediaInfoFunc)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_create_function() failed");
return Undefined(Environment); //undefined
}

napi_value MediaInfoListFunc;
if (napi_create_function(Environment, "MediaInfoList", NAPI_AUTO_LENGTH, CreateMediaInfoListObject, NULL, &MediaInfoListFunc)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_create_function() failed");
return Undefined(Environment); //undefined
}

if (napi_set_named_property(Environment, Exports, "MediaInfo", MediaInfoFunc)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_set_named_property() failed");
return Undefined(Environment); //undefined
}

if (napi_set_named_property(Environment, Exports, "MediaInfoList", MediaInfoListFunc)!=napi_ok)
{
napi_throw_error(Environment, NULL, "internal error: napi_set_named_property() failed");
return Undefined(Environment); //undefined
}

return Exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
Loading

0 comments on commit ead85ed

Please sign in to comment.