├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── publish_node.sh └── src ├── JsPlayer.cpp ├── JsPlayer.h └── module.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | dist/ 4 | CMakeLists.txt.user 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(wcjs-gs) 4 | 5 | add_definitions(-std=c++17) 6 | 7 | find_package(PkgConfig REQUIRED) 8 | pkg_search_module(GSTREAMER REQUIRED gstreamer-1.0) 9 | pkg_search_module(GSTREAMER_APP REQUIRED gstreamer-app-1.0) 10 | pkg_search_module(GSTREAMER_VIDEO_META REQUIRED gstreamer-video-1.0) 11 | pkg_search_module(GSTREAMER_AUDIO_META REQUIRED gstreamer-audio-1.0) 12 | 13 | file(GLOB SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 14 | src/[^.]*.cpp 15 | src/[^.]*.h 16 | *.html 17 | *.js 18 | README.md 19 | package.json 20 | ) 21 | 22 | add_library( ${PROJECT_NAME} SHARED ${SOURCE_FILES} ) 23 | set_target_properties( ${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node") 24 | target_include_directories(${PROJECT_NAME} PUBLIC ${GSTREAMER_INCLUDE_DIRS}) 25 | target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_JS_INC}") 26 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/node_modules") 27 | target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/node_modules/node-addon-api") 28 | target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/node_modules/node-addon-api-helpers") 29 | elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../node_modules") 30 | target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../node-addon-api") 31 | target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../node-addon-api-helpers") 32 | else() 33 | message(FATAL_ERROR "Can't locate node_modules") 34 | endif() 35 | target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB}) 36 | target_link_libraries(${PROJECT_NAME} 37 | ${GSTREAMER_LIBRARIES} 38 | ${GSTREAMER_APP_LIBRARIES} 39 | ${GSTREAMER_VIDEO_META_LIBRARIES} 40 | ${GSTREAMER_AUDIO_META_LIBRARIES}) 41 | 42 | #get_cmake_property( _variableNames VARIABLES ) 43 | #foreach( _variableName ${_variableNames} ) 44 | # message( STATUS "${_variableName}=${${_variableName}}" ) 45 | #endforeach() 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | (This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.) 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | {description} 474 | Copyright (C) {year} {fullname} 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | {signature of Ty Coon}, 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | 506 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebChimera.js 2 | [proof-of-concept] GStreamer binding for Node.js 3 | 4 | [![Join the chat at https://gitter.im/RSATom/WebChimera](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/RSATom/WebChimera?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | ## Npm 7 | * https://www.npmjs.com/package/wcjs-gs 8 | 9 | ## Docs 10 | * [JavaScript API](https://github.com/RSATom/wcjs-gs/wiki/JavaScript-API) 11 | 12 | ## Demos 13 | * [Renderer Demo](https://github.com/RSATom/wcjs-ugly-demo/tree/wcjs-gs) 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require("bindings")("wcjs-gs"); 2 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wcjs-gs", 3 | "version": "0.4.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "wcjs-gs", 9 | "version": "0.4.0", 10 | "hasInstallScript": true, 11 | "license": "LGPL-2.1", 12 | "dependencies": { 13 | "bindings": "~1.5.0", 14 | "cmake-js": "*", 15 | "node-addon-api": "*", 16 | "node-addon-api-helpers": "*" 17 | } 18 | }, 19 | "node_modules/ansi-regex": { 20 | "version": "5.0.1", 21 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 22 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 23 | "license": "MIT", 24 | "engines": { 25 | "node": ">=8" 26 | } 27 | }, 28 | "node_modules/ansi-styles": { 29 | "version": "4.3.0", 30 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 31 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 32 | "license": "MIT", 33 | "dependencies": { 34 | "color-convert": "^2.0.1" 35 | }, 36 | "engines": { 37 | "node": ">=8" 38 | }, 39 | "funding": { 40 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 41 | } 42 | }, 43 | "node_modules/aproba": { 44 | "version": "2.0.0", 45 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", 46 | "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", 47 | "license": "ISC" 48 | }, 49 | "node_modules/are-we-there-yet": { 50 | "version": "3.0.1", 51 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", 52 | "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", 53 | "deprecated": "This package is no longer supported.", 54 | "license": "ISC", 55 | "dependencies": { 56 | "delegates": "^1.0.0", 57 | "readable-stream": "^3.6.0" 58 | }, 59 | "engines": { 60 | "node": "^12.13.0 || ^14.15.0 || >=16.0.0" 61 | } 62 | }, 63 | "node_modules/asynckit": { 64 | "version": "0.4.0", 65 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 66 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", 67 | "license": "MIT" 68 | }, 69 | "node_modules/axios": { 70 | "version": "1.7.7", 71 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", 72 | "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", 73 | "license": "MIT", 74 | "dependencies": { 75 | "follow-redirects": "^1.15.6", 76 | "form-data": "^4.0.0", 77 | "proxy-from-env": "^1.1.0" 78 | } 79 | }, 80 | "node_modules/bindings": { 81 | "version": "1.5.0", 82 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 83 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 84 | "license": "MIT", 85 | "dependencies": { 86 | "file-uri-to-path": "1.0.0" 87 | } 88 | }, 89 | "node_modules/chownr": { 90 | "version": "2.0.0", 91 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", 92 | "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", 93 | "license": "ISC", 94 | "engines": { 95 | "node": ">=10" 96 | } 97 | }, 98 | "node_modules/cliui": { 99 | "version": "8.0.1", 100 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 101 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 102 | "license": "ISC", 103 | "dependencies": { 104 | "string-width": "^4.2.0", 105 | "strip-ansi": "^6.0.1", 106 | "wrap-ansi": "^7.0.0" 107 | }, 108 | "engines": { 109 | "node": ">=12" 110 | } 111 | }, 112 | "node_modules/cmake-js": { 113 | "version": "7.3.0", 114 | "resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-7.3.0.tgz", 115 | "integrity": "sha512-dXs2zq9WxrV87bpJ+WbnGKv8WUBXDw8blNiwNHoRe/it+ptscxhQHKB1SJXa1w+kocLMeP28Tk4/eTCezg4o+w==", 116 | "license": "MIT", 117 | "dependencies": { 118 | "axios": "^1.6.5", 119 | "debug": "^4", 120 | "fs-extra": "^11.2.0", 121 | "lodash.isplainobject": "^4.0.6", 122 | "memory-stream": "^1.0.0", 123 | "node-api-headers": "^1.1.0", 124 | "npmlog": "^6.0.2", 125 | "rc": "^1.2.7", 126 | "semver": "^7.5.4", 127 | "tar": "^6.2.0", 128 | "url-join": "^4.0.1", 129 | "which": "^2.0.2", 130 | "yargs": "^17.7.2" 131 | }, 132 | "bin": { 133 | "cmake-js": "bin/cmake-js" 134 | }, 135 | "engines": { 136 | "node": ">= 14.15.0" 137 | } 138 | }, 139 | "node_modules/color-convert": { 140 | "version": "2.0.1", 141 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 142 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 143 | "license": "MIT", 144 | "dependencies": { 145 | "color-name": "~1.1.4" 146 | }, 147 | "engines": { 148 | "node": ">=7.0.0" 149 | } 150 | }, 151 | "node_modules/color-name": { 152 | "version": "1.1.4", 153 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 154 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 155 | "license": "MIT" 156 | }, 157 | "node_modules/color-support": { 158 | "version": "1.1.3", 159 | "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", 160 | "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", 161 | "license": "ISC", 162 | "bin": { 163 | "color-support": "bin.js" 164 | } 165 | }, 166 | "node_modules/combined-stream": { 167 | "version": "1.0.8", 168 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 169 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 170 | "license": "MIT", 171 | "dependencies": { 172 | "delayed-stream": "~1.0.0" 173 | }, 174 | "engines": { 175 | "node": ">= 0.8" 176 | } 177 | }, 178 | "node_modules/console-control-strings": { 179 | "version": "1.1.0", 180 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 181 | "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", 182 | "license": "ISC" 183 | }, 184 | "node_modules/debug": { 185 | "version": "4.3.7", 186 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", 187 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", 188 | "license": "MIT", 189 | "dependencies": { 190 | "ms": "^2.1.3" 191 | }, 192 | "engines": { 193 | "node": ">=6.0" 194 | }, 195 | "peerDependenciesMeta": { 196 | "supports-color": { 197 | "optional": true 198 | } 199 | } 200 | }, 201 | "node_modules/deep-extend": { 202 | "version": "0.6.0", 203 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 204 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 205 | "license": "MIT", 206 | "engines": { 207 | "node": ">=4.0.0" 208 | } 209 | }, 210 | "node_modules/delayed-stream": { 211 | "version": "1.0.0", 212 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 213 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 214 | "license": "MIT", 215 | "engines": { 216 | "node": ">=0.4.0" 217 | } 218 | }, 219 | "node_modules/delegates": { 220 | "version": "1.0.0", 221 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 222 | "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", 223 | "license": "MIT" 224 | }, 225 | "node_modules/emoji-regex": { 226 | "version": "8.0.0", 227 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 228 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 229 | "license": "MIT" 230 | }, 231 | "node_modules/escalade": { 232 | "version": "3.2.0", 233 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 234 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 235 | "license": "MIT", 236 | "engines": { 237 | "node": ">=6" 238 | } 239 | }, 240 | "node_modules/file-uri-to-path": { 241 | "version": "1.0.0", 242 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 243 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", 244 | "license": "MIT" 245 | }, 246 | "node_modules/follow-redirects": { 247 | "version": "1.15.9", 248 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", 249 | "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", 250 | "funding": [ 251 | { 252 | "type": "individual", 253 | "url": "https://github.com/sponsors/RubenVerborgh" 254 | } 255 | ], 256 | "license": "MIT", 257 | "engines": { 258 | "node": ">=4.0" 259 | }, 260 | "peerDependenciesMeta": { 261 | "debug": { 262 | "optional": true 263 | } 264 | } 265 | }, 266 | "node_modules/form-data": { 267 | "version": "4.0.0", 268 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 269 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 270 | "license": "MIT", 271 | "dependencies": { 272 | "asynckit": "^0.4.0", 273 | "combined-stream": "^1.0.8", 274 | "mime-types": "^2.1.12" 275 | }, 276 | "engines": { 277 | "node": ">= 6" 278 | } 279 | }, 280 | "node_modules/fs-extra": { 281 | "version": "11.2.0", 282 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", 283 | "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", 284 | "license": "MIT", 285 | "dependencies": { 286 | "graceful-fs": "^4.2.0", 287 | "jsonfile": "^6.0.1", 288 | "universalify": "^2.0.0" 289 | }, 290 | "engines": { 291 | "node": ">=14.14" 292 | } 293 | }, 294 | "node_modules/fs-minipass": { 295 | "version": "2.1.0", 296 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", 297 | "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", 298 | "license": "ISC", 299 | "dependencies": { 300 | "minipass": "^3.0.0" 301 | }, 302 | "engines": { 303 | "node": ">= 8" 304 | } 305 | }, 306 | "node_modules/fs-minipass/node_modules/minipass": { 307 | "version": "3.3.6", 308 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", 309 | "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", 310 | "license": "ISC", 311 | "dependencies": { 312 | "yallist": "^4.0.0" 313 | }, 314 | "engines": { 315 | "node": ">=8" 316 | } 317 | }, 318 | "node_modules/gauge": { 319 | "version": "4.0.4", 320 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", 321 | "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", 322 | "deprecated": "This package is no longer supported.", 323 | "license": "ISC", 324 | "dependencies": { 325 | "aproba": "^1.0.3 || ^2.0.0", 326 | "color-support": "^1.1.3", 327 | "console-control-strings": "^1.1.0", 328 | "has-unicode": "^2.0.1", 329 | "signal-exit": "^3.0.7", 330 | "string-width": "^4.2.3", 331 | "strip-ansi": "^6.0.1", 332 | "wide-align": "^1.1.5" 333 | }, 334 | "engines": { 335 | "node": "^12.13.0 || ^14.15.0 || >=16.0.0" 336 | } 337 | }, 338 | "node_modules/get-caller-file": { 339 | "version": "2.0.5", 340 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 341 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 342 | "license": "ISC", 343 | "engines": { 344 | "node": "6.* || 8.* || >= 10.*" 345 | } 346 | }, 347 | "node_modules/graceful-fs": { 348 | "version": "4.2.11", 349 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 350 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 351 | "license": "ISC" 352 | }, 353 | "node_modules/has-unicode": { 354 | "version": "2.0.1", 355 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 356 | "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", 357 | "license": "ISC" 358 | }, 359 | "node_modules/inherits": { 360 | "version": "2.0.4", 361 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 362 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 363 | "license": "ISC" 364 | }, 365 | "node_modules/ini": { 366 | "version": "1.3.8", 367 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 368 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", 369 | "license": "ISC" 370 | }, 371 | "node_modules/is-fullwidth-code-point": { 372 | "version": "3.0.0", 373 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 374 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 375 | "license": "MIT", 376 | "engines": { 377 | "node": ">=8" 378 | } 379 | }, 380 | "node_modules/isexe": { 381 | "version": "2.0.0", 382 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 383 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 384 | "license": "ISC" 385 | }, 386 | "node_modules/jsonfile": { 387 | "version": "6.1.0", 388 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 389 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 390 | "license": "MIT", 391 | "dependencies": { 392 | "universalify": "^2.0.0" 393 | }, 394 | "optionalDependencies": { 395 | "graceful-fs": "^4.1.6" 396 | } 397 | }, 398 | "node_modules/lodash.isplainobject": { 399 | "version": "4.0.6", 400 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 401 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", 402 | "license": "MIT" 403 | }, 404 | "node_modules/memory-stream": { 405 | "version": "1.0.0", 406 | "resolved": "https://registry.npmjs.org/memory-stream/-/memory-stream-1.0.0.tgz", 407 | "integrity": "sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww==", 408 | "license": "MIT", 409 | "dependencies": { 410 | "readable-stream": "^3.4.0" 411 | } 412 | }, 413 | "node_modules/mime-db": { 414 | "version": "1.52.0", 415 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 416 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 417 | "license": "MIT", 418 | "engines": { 419 | "node": ">= 0.6" 420 | } 421 | }, 422 | "node_modules/mime-types": { 423 | "version": "2.1.35", 424 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 425 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 426 | "license": "MIT", 427 | "dependencies": { 428 | "mime-db": "1.52.0" 429 | }, 430 | "engines": { 431 | "node": ">= 0.6" 432 | } 433 | }, 434 | "node_modules/minimist": { 435 | "version": "1.2.8", 436 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 437 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 438 | "license": "MIT", 439 | "funding": { 440 | "url": "https://github.com/sponsors/ljharb" 441 | } 442 | }, 443 | "node_modules/minipass": { 444 | "version": "5.0.0", 445 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", 446 | "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", 447 | "license": "ISC", 448 | "engines": { 449 | "node": ">=8" 450 | } 451 | }, 452 | "node_modules/minizlib": { 453 | "version": "2.1.2", 454 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", 455 | "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", 456 | "license": "MIT", 457 | "dependencies": { 458 | "minipass": "^3.0.0", 459 | "yallist": "^4.0.0" 460 | }, 461 | "engines": { 462 | "node": ">= 8" 463 | } 464 | }, 465 | "node_modules/minizlib/node_modules/minipass": { 466 | "version": "3.3.6", 467 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", 468 | "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", 469 | "license": "ISC", 470 | "dependencies": { 471 | "yallist": "^4.0.0" 472 | }, 473 | "engines": { 474 | "node": ">=8" 475 | } 476 | }, 477 | "node_modules/mkdirp": { 478 | "version": "1.0.4", 479 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 480 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 481 | "license": "MIT", 482 | "bin": { 483 | "mkdirp": "bin/cmd.js" 484 | }, 485 | "engines": { 486 | "node": ">=10" 487 | } 488 | }, 489 | "node_modules/ms": { 490 | "version": "2.1.3", 491 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 492 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 493 | "license": "MIT" 494 | }, 495 | "node_modules/node-addon-api": { 496 | "version": "8.1.0", 497 | "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.1.0.tgz", 498 | "integrity": "sha512-yBY+qqWSv3dWKGODD6OGE6GnTX7Q2r+4+DfpqxHSHh8x0B4EKP9+wVGLS6U/AM1vxSNNmUEuIV5EGhYwPpfOwQ==", 499 | "license": "MIT", 500 | "engines": { 501 | "node": "^18 || ^20 || >= 21" 502 | } 503 | }, 504 | "node_modules/node-addon-api-helpers": { 505 | "version": "0.11.0", 506 | "resolved": "https://registry.npmjs.org/node-addon-api-helpers/-/node-addon-api-helpers-0.11.0.tgz", 507 | "integrity": "sha512-8y3oQE1U/srz1gjX8MyrkrrP49qmoTu50WrojoBtmYh/bMllP0IigQQ67dLVmeKwTCpNJYMLrtvbQ2zxivZ4Hw==", 508 | "license": "MIT" 509 | }, 510 | "node_modules/node-api-headers": { 511 | "version": "1.3.0", 512 | "resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.3.0.tgz", 513 | "integrity": "sha512-8Bviwtw4jNhv0B2qDjj4M5e6GyAuGtxsmZTrFJu3S3Z0+oHwIgSUdIKkKJmZd+EbMo7g3v4PLBbrjxwmZOqMBg==", 514 | "license": "MIT" 515 | }, 516 | "node_modules/npmlog": { 517 | "version": "6.0.2", 518 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", 519 | "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", 520 | "deprecated": "This package is no longer supported.", 521 | "license": "ISC", 522 | "dependencies": { 523 | "are-we-there-yet": "^3.0.0", 524 | "console-control-strings": "^1.1.0", 525 | "gauge": "^4.0.3", 526 | "set-blocking": "^2.0.0" 527 | }, 528 | "engines": { 529 | "node": "^12.13.0 || ^14.15.0 || >=16.0.0" 530 | } 531 | }, 532 | "node_modules/proxy-from-env": { 533 | "version": "1.1.0", 534 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 535 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", 536 | "license": "MIT" 537 | }, 538 | "node_modules/rc": { 539 | "version": "1.2.8", 540 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 541 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 542 | "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", 543 | "dependencies": { 544 | "deep-extend": "^0.6.0", 545 | "ini": "~1.3.0", 546 | "minimist": "^1.2.0", 547 | "strip-json-comments": "~2.0.1" 548 | }, 549 | "bin": { 550 | "rc": "cli.js" 551 | } 552 | }, 553 | "node_modules/readable-stream": { 554 | "version": "3.6.2", 555 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 556 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 557 | "license": "MIT", 558 | "dependencies": { 559 | "inherits": "^2.0.3", 560 | "string_decoder": "^1.1.1", 561 | "util-deprecate": "^1.0.1" 562 | }, 563 | "engines": { 564 | "node": ">= 6" 565 | } 566 | }, 567 | "node_modules/require-directory": { 568 | "version": "2.1.1", 569 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 570 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 571 | "license": "MIT", 572 | "engines": { 573 | "node": ">=0.10.0" 574 | } 575 | }, 576 | "node_modules/safe-buffer": { 577 | "version": "5.2.1", 578 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 579 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 580 | "funding": [ 581 | { 582 | "type": "github", 583 | "url": "https://github.com/sponsors/feross" 584 | }, 585 | { 586 | "type": "patreon", 587 | "url": "https://www.patreon.com/feross" 588 | }, 589 | { 590 | "type": "consulting", 591 | "url": "https://feross.org/support" 592 | } 593 | ], 594 | "license": "MIT" 595 | }, 596 | "node_modules/semver": { 597 | "version": "7.6.3", 598 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", 599 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", 600 | "license": "ISC", 601 | "bin": { 602 | "semver": "bin/semver.js" 603 | }, 604 | "engines": { 605 | "node": ">=10" 606 | } 607 | }, 608 | "node_modules/set-blocking": { 609 | "version": "2.0.0", 610 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 611 | "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", 612 | "license": "ISC" 613 | }, 614 | "node_modules/signal-exit": { 615 | "version": "3.0.7", 616 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", 617 | "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", 618 | "license": "ISC" 619 | }, 620 | "node_modules/string_decoder": { 621 | "version": "1.3.0", 622 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 623 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 624 | "license": "MIT", 625 | "dependencies": { 626 | "safe-buffer": "~5.2.0" 627 | } 628 | }, 629 | "node_modules/string-width": { 630 | "version": "4.2.3", 631 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 632 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 633 | "license": "MIT", 634 | "dependencies": { 635 | "emoji-regex": "^8.0.0", 636 | "is-fullwidth-code-point": "^3.0.0", 637 | "strip-ansi": "^6.0.1" 638 | }, 639 | "engines": { 640 | "node": ">=8" 641 | } 642 | }, 643 | "node_modules/strip-ansi": { 644 | "version": "6.0.1", 645 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 646 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 647 | "license": "MIT", 648 | "dependencies": { 649 | "ansi-regex": "^5.0.1" 650 | }, 651 | "engines": { 652 | "node": ">=8" 653 | } 654 | }, 655 | "node_modules/strip-json-comments": { 656 | "version": "2.0.1", 657 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 658 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 659 | "license": "MIT", 660 | "engines": { 661 | "node": ">=0.10.0" 662 | } 663 | }, 664 | "node_modules/tar": { 665 | "version": "6.2.1", 666 | "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", 667 | "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", 668 | "license": "ISC", 669 | "dependencies": { 670 | "chownr": "^2.0.0", 671 | "fs-minipass": "^2.0.0", 672 | "minipass": "^5.0.0", 673 | "minizlib": "^2.1.1", 674 | "mkdirp": "^1.0.3", 675 | "yallist": "^4.0.0" 676 | }, 677 | "engines": { 678 | "node": ">=10" 679 | } 680 | }, 681 | "node_modules/universalify": { 682 | "version": "2.0.1", 683 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 684 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 685 | "license": "MIT", 686 | "engines": { 687 | "node": ">= 10.0.0" 688 | } 689 | }, 690 | "node_modules/url-join": { 691 | "version": "4.0.1", 692 | "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", 693 | "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", 694 | "license": "MIT" 695 | }, 696 | "node_modules/util-deprecate": { 697 | "version": "1.0.2", 698 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 699 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 700 | "license": "MIT" 701 | }, 702 | "node_modules/which": { 703 | "version": "2.0.2", 704 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 705 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 706 | "license": "ISC", 707 | "dependencies": { 708 | "isexe": "^2.0.0" 709 | }, 710 | "bin": { 711 | "node-which": "bin/node-which" 712 | }, 713 | "engines": { 714 | "node": ">= 8" 715 | } 716 | }, 717 | "node_modules/wide-align": { 718 | "version": "1.1.5", 719 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", 720 | "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", 721 | "license": "ISC", 722 | "dependencies": { 723 | "string-width": "^1.0.2 || 2 || 3 || 4" 724 | } 725 | }, 726 | "node_modules/wrap-ansi": { 727 | "version": "7.0.0", 728 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 729 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 730 | "license": "MIT", 731 | "dependencies": { 732 | "ansi-styles": "^4.0.0", 733 | "string-width": "^4.1.0", 734 | "strip-ansi": "^6.0.0" 735 | }, 736 | "engines": { 737 | "node": ">=10" 738 | }, 739 | "funding": { 740 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 741 | } 742 | }, 743 | "node_modules/y18n": { 744 | "version": "5.0.8", 745 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 746 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 747 | "license": "ISC", 748 | "engines": { 749 | "node": ">=10" 750 | } 751 | }, 752 | "node_modules/yallist": { 753 | "version": "4.0.0", 754 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 755 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 756 | "license": "ISC" 757 | }, 758 | "node_modules/yargs": { 759 | "version": "17.7.2", 760 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 761 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 762 | "license": "MIT", 763 | "dependencies": { 764 | "cliui": "^8.0.1", 765 | "escalade": "^3.1.1", 766 | "get-caller-file": "^2.0.5", 767 | "require-directory": "^2.1.1", 768 | "string-width": "^4.2.3", 769 | "y18n": "^5.0.5", 770 | "yargs-parser": "^21.1.1" 771 | }, 772 | "engines": { 773 | "node": ">=12" 774 | } 775 | }, 776 | "node_modules/yargs-parser": { 777 | "version": "21.1.1", 778 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 779 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 780 | "license": "ISC", 781 | "engines": { 782 | "node": ">=12" 783 | } 784 | } 785 | } 786 | } 787 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wcjs-gs", 3 | "description": "WebChimera.js GStreamer edition", 4 | "version": "0.5.3", 5 | "license": "LGPL-2.1", 6 | "author": "Sergey Radionov ", 7 | "keywords": [ 8 | "wcjs", 9 | "gstreamer" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/RSATom/wcjs-gs" 14 | }, 15 | "dependencies": { 16 | "bindings": "~1.5.0", 17 | "cmake-js": "*", 18 | "node-addon-api": "*", 19 | "node-addon-api-helpers": "*" 20 | }, 21 | "scripts": { 22 | "install": "npx cmake-js compile" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /publish_node.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | npm install 6 | 7 | rm -r ./dist || true 8 | mkdir dist 9 | 10 | cp ./build/Release/wcjs-gs.node ./README.md ./dist/ 11 | 12 | cat < ./dist/index.js 13 | module.exports = require("./wcjs-gs.node"); 14 | EOF 15 | 16 | cat < ./dist/package.json 17 | { 18 | "name": "wcjs-gs-prebuilt", 19 | "description": "WebChimera.js GStreamer edition", 20 | "version": "`node -p "require('./package.json').version"`", 21 | "license": "LGPL-2.1", 22 | "author": "Sergey Radionov ", 23 | "keywords": [ 24 | "wcjs", 25 | "gstreamer" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/RSATom/wcjs-gs" 30 | } 31 | } 32 | EOF 33 | 34 | cd dist 35 | npm publish 36 | 37 | cd - 38 | -------------------------------------------------------------------------------- /src/JsPlayer.cpp: -------------------------------------------------------------------------------- 1 | #include "JsPlayer.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | namespace { 10 | 11 | enum class StreamType 12 | { 13 | Audio, 14 | Video, 15 | Other, 16 | }; 17 | 18 | StreamType GetStreamType(const gchar* capsName) { 19 | if(g_str_has_prefix(capsName, "audio/")) 20 | return StreamType::Audio; 21 | else if(g_str_has_prefix(capsName, "video/")) 22 | return StreamType::Video; 23 | else 24 | return StreamType::Other; 25 | } 26 | 27 | void SetAudioProperties(Napi::Object* object, const GstAudioInfo& audioInfo) { 28 | if(audioInfo.channels) 29 | object->Set("channels", ToJsValue(object->Env(), audioInfo.channels)); 30 | if(audioInfo.rate) 31 | object->Set("samplingRate", ToJsValue(object->Env(), audioInfo.rate)); 32 | if(audioInfo.bpf) 33 | object->Set("sampleSize", ToJsValue(object->Env(), audioInfo.bpf)); 34 | } 35 | 36 | void SetVideoProperties(Napi::Object* object, const GstVideoInfo& videoInfo) { 37 | object->Set("pixelFormat", ToJsValue(object->Env(), videoInfo.finfo->name)); 38 | if(videoInfo.width) 39 | object->Set("width", ToJsValue(object->Env(), videoInfo.width)); 40 | if(videoInfo.height) 41 | object->Set("height", ToJsValue(object->Env(), videoInfo.height)); 42 | } 43 | 44 | } 45 | 46 | struct JsPlayer::AppSinkData { 47 | AppSinkData(Napi::FunctionReference&& callback) : 48 | callback(std::move(callback)) {} 49 | AppSinkData(const AppSinkData& d) = delete; 50 | AppSinkData(AppSinkData&& d) : 51 | type(d.type), 52 | prerolled(d.prerolled), 53 | firstSample(d.firstSample), 54 | eos(d.eos), 55 | callback(std::move(d.callback)) {} 56 | 57 | std::optional type; 58 | std::string mediaType; 59 | std::optional audioInfo; 60 | std::optional videoInfo; 61 | 62 | bool prerolled = false; 63 | bool firstSample = true; 64 | bool eos = false; 65 | 66 | Napi::FunctionReference callback; 67 | }; 68 | 69 | struct JsPlayer::PadProbeData { 70 | PadProbeData(Napi::FunctionReference&& callback) : 71 | callback(std::move(callback)) {} 72 | PadProbeData(const AppSinkData& d) = delete; 73 | PadProbeData(AppSinkData&& d) : 74 | callback(std::move(d.callback)) {} 75 | 76 | Napi::FunctionReference callback; 77 | }; 78 | 79 | struct JsPlayer::AsyncEvent 80 | { 81 | protected: 82 | AsyncEvent() = default; 83 | 84 | public: 85 | AsyncEvent(const AsyncEvent&) = delete; 86 | AsyncEvent& operator = (const AsyncEvent&) = delete; 87 | 88 | virtual ~AsyncEvent() {}; 89 | 90 | virtual void forwardTo(JsPlayer*) const = 0; 91 | }; 92 | 93 | struct JsPlayer::CapsChangedEvent : public JsPlayer::AsyncEvent 94 | { 95 | CapsChangedEvent(GstPad* pad, GstCaps* caps) : 96 | pad(GST_PAD(gst_object_ref(pad))), 97 | caps(gst_caps_ref(caps)) {} 98 | CapsChangedEvent(CapsChangedEvent&& source) : 99 | pad(source.pad), 100 | caps(source.caps) 101 | { 102 | source.pad = nullptr; 103 | source.caps = nullptr; 104 | } 105 | ~CapsChangedEvent() override { 106 | if(caps) 107 | gst_caps_unref(caps); 108 | 109 | if(pad) 110 | gst_object_unref(pad); 111 | } 112 | 113 | void forwardTo(JsPlayer* player) const override { 114 | player->onCapsChanged(pad, caps); 115 | } 116 | 117 | GstPad* pad; 118 | GstCaps* caps; 119 | }; 120 | 121 | struct JsPlayer::EosEvent : public JsPlayer::AsyncEvent 122 | { 123 | void forwardTo(JsPlayer* player) const override { 124 | player->onEos(); 125 | } 126 | }; 127 | 128 | /////////////////////////////////////////////////////////////////////////////// 129 | Napi::FunctionReference JsPlayer::_jsConstructor; 130 | 131 | Napi::Object JsPlayer::InitJsApi(Napi::Env env, Napi::Object exports) 132 | { 133 | gst_init(0, 0); 134 | 135 | Napi::HandleScope scope(env); 136 | 137 | Napi::Function func = 138 | DefineClass(env, "JsPlayer", { 139 | InstanceValue("GST_STATE_VOID_PENDING", ToJsValue(env, GST_STATE_VOID_PENDING)), 140 | InstanceValue("GST_STATE_NULL", ToJsValue(env, GST_STATE_NULL)), 141 | InstanceValue("GST_STATE_READY", ToJsValue(env, GST_STATE_READY)), 142 | InstanceValue("GST_STATE_PAUSED", ToJsValue(env, GST_STATE_PAUSED)), 143 | InstanceValue("GST_STATE_PLAYING", ToJsValue(env, GST_STATE_PLAYING)), 144 | InstanceValue("AppSinkSetup", ToJsValue(env, Setup)), 145 | InstanceValue("AppSinkNewPreroll", ToJsValue(env, NewPreroll)), 146 | InstanceValue("AppSinkNewSample", ToJsValue(env, NewSample)), 147 | InstanceValue("AppSinkEos", ToJsValue(env, Eos)), 148 | CLASS_METHOD("parseLaunch", &JsPlayer::parseLaunch), 149 | CLASS_METHOD("addAppSinkCallback", &JsPlayer::addAppSinkCallback), 150 | CLASS_METHOD("addCapsProbe", &JsPlayer::addCapsProbe), 151 | CLASS_METHOD("setState", &JsPlayer::setState), 152 | CLASS_METHOD("sendEos", &JsPlayer::sendEos), 153 | } 154 | ); 155 | 156 | _jsConstructor = Napi::Persistent(func); 157 | _jsConstructor.SuppressDestruct(); 158 | 159 | exports.Set("JsPlayer", func); 160 | 161 | return exports; 162 | } 163 | 164 | JsPlayer::JsPlayer(const Napi::CallbackInfo& info) : 165 | Napi::ObjectWrap(info), 166 | _pipeline(nullptr) 167 | { 168 | if(info.Length() > 0) { 169 | Napi::Value arg0 = info[0]; 170 | if(arg0.IsFunction()) 171 | _eosCallback = Napi::Persistent(arg0.As()); 172 | } 173 | 174 | uv_loop_t* loop = uv_default_loop(); 175 | 176 | _queueAsync = new uv_async_t; 177 | uv_async_init(loop, _queueAsync, 178 | [] (uv_async_t* handle) { 179 | if(handle->data) 180 | reinterpret_cast(handle->data)->handleQueue(); 181 | } 182 | ); 183 | _queueAsync->data = this; 184 | 185 | _async = new uv_async_t; 186 | uv_async_init(loop, _async, 187 | [] (uv_async_t* handle) { 188 | if(handle->data) 189 | reinterpret_cast(handle->data)->handleAsync(); 190 | } 191 | ); 192 | _async->data = this; 193 | } 194 | 195 | JsPlayer::~JsPlayer() 196 | { 197 | close(); 198 | } 199 | 200 | void JsPlayer::cleanup() 201 | { 202 | if(_pipeline) { 203 | setState(GST_STATE_NULL); 204 | 205 | for(const auto& pair: _padsProbes) { 206 | gst_object_unref(pair.first); 207 | } 208 | _padsProbes.clear(); 209 | 210 | for(const auto& pair: _appSinks) { 211 | gst_object_unref(pair.first); 212 | } 213 | _appSinks.clear(); 214 | 215 | gst_object_unref(_pipeline); 216 | _pipeline = nullptr; 217 | } 218 | } 219 | 220 | void JsPlayer::close() 221 | { 222 | cleanup(); 223 | 224 | _queueAsync->data = nullptr; 225 | uv_close( 226 | reinterpret_cast(_queueAsync), 227 | [] (uv_handle_s* handle) { 228 | delete reinterpret_cast(handle); 229 | }); 230 | _queueAsync = nullptr; 231 | 232 | _async->data = nullptr; 233 | uv_close( 234 | reinterpret_cast(_async), 235 | [] (uv_handle_s* handle) { 236 | delete reinterpret_cast(handle); 237 | }); 238 | _async = nullptr; 239 | } 240 | 241 | void JsPlayer::handleAsync() 242 | { 243 | Napi::HandleScope scope(Env()); 244 | 245 | for(auto& pair: _appSinks) { 246 | GstAppSink* appSink = pair.first; 247 | AppSinkData& appSinkData = pair.second; 248 | if(appSinkData.eos) continue; 249 | 250 | if(!appSinkData.prerolled) { 251 | if(g_autoptr(GstSample) prerollSample = gst_app_sink_try_pull_preroll(appSink, 0)) { 252 | onSample(&appSinkData, prerollSample, true); 253 | appSinkData.prerolled = true; 254 | } 255 | } 256 | 257 | while(g_autoptr(GstSample) sample = gst_app_sink_try_pull_sample(appSink, 0)) { 258 | onSample(&appSinkData, sample, false); 259 | } 260 | 261 | appSinkData.eos = gst_app_sink_is_eos(appSink); 262 | if(appSinkData.eos) { 263 | onEos(appSink); 264 | } 265 | } 266 | } 267 | 268 | void JsPlayer::onSetup(JsPlayer::AppSinkData* sinkData) 269 | { 270 | assert(sinkData && sinkData->type.has_value()); 271 | if(!sinkData || !sinkData->type.has_value() || sinkData->callback.IsEmpty()) 272 | return; 273 | 274 | switch(sinkData->type.value()) { 275 | case StreamType::Audio: { 276 | assert(sinkData->audioInfo.has_value()); 277 | if(!sinkData->audioInfo.has_value()) 278 | break; 279 | 280 | const GstAudioInfo& audioInfo = sinkData->audioInfo.value(); 281 | 282 | Napi::Object propertiesObject = Napi::Object::New(Env()); 283 | SetAudioProperties(&propertiesObject, audioInfo); 284 | 285 | sinkData->callback.Call({ 286 | ToJsValue(Env(), Setup), 287 | ToJsValue(Env(), sinkData->mediaType), 288 | propertiesObject, 289 | }); 290 | break; 291 | } 292 | case StreamType::Video: { 293 | assert(sinkData->videoInfo.has_value()); 294 | if(!sinkData->videoInfo.has_value()) 295 | break; 296 | 297 | const GstVideoInfo& videoInfo = sinkData->videoInfo.value(); 298 | 299 | Napi::Object propertiesObject = Napi::Object::New(Env()); 300 | SetVideoProperties(&propertiesObject, videoInfo); 301 | 302 | sinkData->callback.Call({ 303 | ToJsValue(Env(), Setup), 304 | ToJsValue(Env(), sinkData->mediaType), 305 | propertiesObject, 306 | }); 307 | break; 308 | } 309 | case StreamType::Other: { 310 | Napi::Object propertiesObject = Napi::Object::New(Env()); 311 | 312 | sinkData->callback.Call({ 313 | ToJsValue(Env(), Setup), 314 | ToJsValue(Env(), sinkData->mediaType), 315 | propertiesObject, 316 | }); 317 | break; 318 | } 319 | } 320 | } 321 | 322 | void JsPlayer::onAudioSample( 323 | AppSinkData* sinkData, 324 | GstSample* sample, 325 | bool preroll) 326 | { 327 | if(!sinkData || sinkData->callback.IsEmpty()) 328 | return; 329 | 330 | GstBuffer* buffer = gst_sample_get_buffer(sample); 331 | if(!buffer) 332 | return; 333 | 334 | GstMapInfo mapInfo; 335 | if(gst_buffer_map(buffer, &mapInfo, GST_MAP_READ)) { 336 | Napi::Buffer sample = 337 | Napi::Buffer::Copy(Env(), mapInfo.data, mapInfo.size); 338 | Napi::Object sampleObject(Env(), sample); 339 | 340 | sinkData->callback.Call({ 341 | ToJsValue(Env(), (preroll ? NewPreroll : NewSample)), 342 | sampleObject, 343 | }); 344 | gst_buffer_unmap(buffer, &mapInfo); 345 | } 346 | } 347 | 348 | void JsPlayer::onVideoSample( 349 | AppSinkData* sinkData, 350 | GstSample* sample, 351 | bool preroll) 352 | { 353 | if(!sinkData || !sinkData->videoInfo || sinkData->callback.IsEmpty()) 354 | return; 355 | 356 | const GstVideoInfo& videoInfo = sinkData->videoInfo.value(); 357 | 358 | GstBuffer* buffer = gst_sample_get_buffer(sample); 359 | if(!buffer) 360 | return; 361 | 362 | GstMapInfo mapInfo; 363 | if(gst_buffer_map(buffer, &mapInfo, GST_MAP_READ)) { 364 | Napi::Buffer sample = 365 | Napi::Buffer::Copy(Env(), mapInfo.data, mapInfo.size); 366 | Napi::Object sampleObject(Env(), sample); 367 | sampleObject.Set("width", ToJsValue(Env(), videoInfo.width)); 368 | sampleObject.Set("height", ToJsValue(Env(), videoInfo.height)); 369 | 370 | if(videoInfo.finfo->n_planes) { 371 | Napi::Array planesArray = Napi::Array::New(Env(), videoInfo.finfo->n_planes); 372 | for(guint p = 0; p < videoInfo.finfo->n_planes; ++p) 373 | planesArray.Set(p, ToJsValue(Env(), static_cast(videoInfo.offset[p]))); 374 | 375 | sampleObject.Set("planes", planesArray); 376 | } 377 | 378 | sinkData->callback.Call({ 379 | ToJsValue(Env(), (preroll ? NewPreroll : NewSample)), 380 | sampleObject, 381 | }); 382 | gst_buffer_unmap(buffer, &mapInfo); 383 | } 384 | } 385 | 386 | void JsPlayer::onOtherSample( 387 | AppSinkData* sinkData, 388 | GstSample* sample, 389 | bool preroll) 390 | { 391 | if(!sinkData || sinkData->callback.IsEmpty()) 392 | return; 393 | 394 | GstBuffer* buffer = gst_sample_get_buffer(sample); 395 | if(!buffer) 396 | return; 397 | 398 | GstMapInfo mapInfo; 399 | if(gst_buffer_map(buffer, &mapInfo, GST_MAP_READ)) { 400 | Napi::Buffer sample = 401 | Napi::Buffer::Copy(Env(), mapInfo.data, mapInfo.size); 402 | Napi::Object sampleObject(Env(), sample); 403 | 404 | sinkData->callback.Call({ 405 | ToJsValue(Env(), (preroll ? NewPreroll : NewSample)), 406 | sampleObject, 407 | }); 408 | gst_buffer_unmap(buffer, &mapInfo); 409 | } 410 | } 411 | 412 | void JsPlayer::onSample( 413 | AppSinkData* sinkData, 414 | GstSample* sample, 415 | bool preroll) 416 | { 417 | if(!sample) 418 | return; 419 | 420 | if(!sinkData->type) { 421 | const gchar* capsName = ""; 422 | GstCaps* caps = gst_sample_get_caps(sample); 423 | if(caps) { 424 | GstStructure* capsStructure = gst_caps_get_structure(caps, 0); 425 | capsName = gst_structure_get_name(capsStructure); 426 | sinkData->mediaType = capsName; 427 | } 428 | 429 | sinkData->type = GetStreamType(capsName); 430 | switch(*sinkData->type) { 431 | case StreamType::Audio: { 432 | GstAudioInfo audioInfo; 433 | if(gst_audio_info_from_caps(&audioInfo, caps)) { 434 | sinkData->audioInfo.emplace(audioInfo); 435 | } 436 | break; 437 | } 438 | case StreamType::Video: { 439 | GstVideoInfo videoInfo; 440 | if(gst_video_info_from_caps(&videoInfo, caps)) { 441 | sinkData->videoInfo.emplace(videoInfo); 442 | } 443 | break; 444 | } 445 | case StreamType::Other: 446 | break; 447 | } 448 | } 449 | 450 | if(sinkData->firstSample) { 451 | onSetup(sinkData); 452 | sinkData->firstSample = false; 453 | } 454 | 455 | switch(*sinkData->type) { 456 | case StreamType::Audio: 457 | onAudioSample(sinkData, sample, preroll); 458 | break; 459 | case StreamType::Video: 460 | onVideoSample(sinkData, sample, preroll); 461 | break; 462 | case StreamType::Other: 463 | onOtherSample(sinkData, sample, preroll); 464 | break; 465 | } 466 | } 467 | 468 | void JsPlayer::onEos(GstAppSink* appSink) 469 | { 470 | if(!appSink) 471 | return; 472 | 473 | auto it = _appSinks.find(appSink); 474 | if(_appSinks.end() == it) 475 | return; 476 | 477 | if(it->second.callback.IsEmpty()) 478 | return; 479 | 480 | it->second.callback.Call({ 481 | ToJsValue(Env(), Eos), 482 | }); 483 | } 484 | 485 | void JsPlayer::onCapsChanged(GstPad* pad, GstCaps* caps) 486 | { 487 | if(!pad || !caps) 488 | return; 489 | 490 | auto it = _padsProbes.find(pad); 491 | if(_padsProbes.end() == it) 492 | return; 493 | 494 | if(it->second.callback.IsEmpty()) 495 | return; 496 | 497 | Napi::HandleScope scope(Env()); 498 | 499 | GstStructure* capsStructure = gst_caps_get_structure(caps, 0); 500 | const gchar* capsName = gst_structure_get_name(capsStructure); 501 | const StreamType type = GetStreamType(capsName); 502 | switch(type) { 503 | case StreamType::Audio: { 504 | GstAudioInfo audioInfo; 505 | if(gst_audio_info_from_caps(&audioInfo, caps)) { 506 | Napi::Object propertiesObject = Napi::Object::New(Env()); 507 | SetAudioProperties(&propertiesObject, audioInfo); 508 | 509 | it->second.callback.Call({ 510 | ToJsValue(Env(), capsName), 511 | propertiesObject, 512 | }); 513 | } 514 | break; 515 | } 516 | case StreamType::Video: { 517 | GstVideoInfo videoInfo; 518 | if(gst_video_info_from_caps(&videoInfo, caps)) { 519 | Napi::Object propertiesObject = Napi::Object::New(Env()); 520 | SetVideoProperties(&propertiesObject, videoInfo); 521 | 522 | it->second.callback.Call({ 523 | ToJsValue(Env(), capsName), 524 | propertiesObject, 525 | }); 526 | } 527 | break; 528 | } 529 | case StreamType::Other: { 530 | Napi::Object propertiesObject = Napi::Object::New(Env()); 531 | 532 | it->second.callback.Call({ 533 | ToJsValue(Env(), capsName), 534 | propertiesObject, 535 | }); 536 | break; 537 | } 538 | } 539 | } 540 | 541 | void JsPlayer::onEos() 542 | { 543 | if(_eosCallback.IsEmpty()) 544 | return; 545 | 546 | handleAsync(); // just in case to don't miss queued samples 547 | 548 | Napi::HandleScope scope(Env()); 549 | _eosCallback.Call({}); 550 | } 551 | 552 | void JsPlayer::handleQueue() 553 | { 554 | _queueGuard.lock(); 555 | std::deque> tmpQueue = std::move(_queue); 556 | _queueGuard.unlock(); 557 | 558 | for(const std::unique_ptr& event: tmpQueue) { 559 | event->forwardTo(this); 560 | } 561 | } 562 | 563 | bool JsPlayer::parseLaunch(const std::string& pipelineDescription) 564 | { 565 | cleanup(); 566 | 567 | GError* error = nullptr; 568 | _pipeline = gst_parse_launch(pipelineDescription.c_str(), &error); 569 | 570 | if(!_pipeline) 571 | return false; 572 | 573 | GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(_pipeline)); 574 | gst_bus_set_sync_handler( 575 | bus, 576 | [] (GstBus*, GstMessage* message, gpointer userData) -> GstBusSyncReply { 577 | if(GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) { 578 | JsPlayer* player = static_cast(userData); 579 | 580 | std::lock_guard(player->_queueGuard); 581 | player->_queue.emplace_back(std::make_unique()); 582 | uv_async_send(player->_queueAsync); 583 | } 584 | 585 | return GST_BUS_PASS; 586 | }, 587 | this, 588 | nullptr); 589 | gst_object_unref(bus); 590 | 591 | return true; 592 | } 593 | 594 | bool JsPlayer::addAppSinkCallback( 595 | const std::string& appSinkName, 596 | const Napi::Function& callback) 597 | { 598 | if(!_pipeline || appSinkName.empty()) 599 | return false; 600 | 601 | g_autoptr(GstElement) sink = gst_bin_get_by_name(GST_BIN(_pipeline), appSinkName.c_str()); 602 | if(!sink) 603 | return false; 604 | 605 | GstAppSink* appSink = GST_APP_SINK_CAST(sink); 606 | if(!appSink) 607 | return false; 608 | 609 | if(callback.IsEmpty()) 610 | return false; 611 | 612 | auto it = _appSinks.find(appSink); 613 | if(_appSinks.end() == it) { 614 | GstAppSinkCallbacks callbacks = { 615 | [] (GstAppSink*, gpointer userData) { 616 | uv_async_send(static_cast(userData)->_async); 617 | }, 618 | [] (GstAppSink*, gpointer userData) -> GstFlowReturn { 619 | uv_async_send(static_cast(userData)->_async); 620 | return GST_FLOW_OK; 621 | }, 622 | [] (GstAppSink*, gpointer userData) -> GstFlowReturn { 623 | uv_async_send(static_cast(userData)->_async); 624 | return GST_FLOW_OK; 625 | } }; 626 | gst_app_sink_set_callbacks(appSink, &callbacks, this, nullptr); 627 | _appSinks.emplace(appSink, Napi::Persistent(callback)); 628 | sink = nullptr; 629 | } else { 630 | it->second.callback = std::move(Napi::Persistent(callback)); 631 | } 632 | 633 | return true; 634 | } 635 | 636 | bool JsPlayer::addCapsProbe( 637 | const std::string& elementName, 638 | const std::string& padName, 639 | const Napi::Function& callback) 640 | { 641 | if(!_pipeline || elementName.empty() || padName.empty()) 642 | return false; 643 | 644 | g_autoptr(GstElement) element = gst_bin_get_by_name(GST_BIN(_pipeline), elementName.c_str()); 645 | if(!element) 646 | return false; 647 | 648 | g_autoptr(GstPad) pad = gst_element_get_static_pad(element, padName.c_str()); 649 | if(!pad) 650 | return false; 651 | 652 | if(_padsProbes.find(pad) != _padsProbes.end()) 653 | return false; 654 | 655 | const gulong probeId = gst_pad_add_probe( 656 | pad, 657 | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, 658 | [] (GstPad* pad, GstPadProbeInfo* info, gpointer userData) -> GstPadProbeReturn { 659 | if(GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_CAPS) 660 | return GST_PAD_PROBE_OK; 661 | 662 | GstEvent* event = GST_EVENT_CAST(GST_PAD_PROBE_INFO_DATA(info)); 663 | GstCaps* caps = nullptr; 664 | gst_event_parse_caps(event, &caps); 665 | 666 | JsPlayer* player = static_cast(userData); 667 | 668 | std::lock_guard(player->_queueGuard); 669 | player->_queue.emplace_back(std::make_unique(pad, caps)); 670 | uv_async_send(player->_queueAsync); 671 | 672 | return GST_PAD_PROBE_OK; 673 | }, 674 | this, 675 | nullptr); 676 | if(!probeId) 677 | return false; 678 | 679 | _padsProbes.emplace(pad, Napi::Persistent(callback)); 680 | pad = nullptr; 681 | 682 | return true; 683 | } 684 | 685 | void JsPlayer::setState(unsigned state) 686 | { 687 | if(_pipeline) 688 | gst_element_set_state(_pipeline, static_cast(state)); 689 | } 690 | 691 | void JsPlayer::sendEos() 692 | { 693 | if(_pipeline) 694 | gst_element_send_event(_pipeline, gst_event_new_eos()); 695 | } 696 | -------------------------------------------------------------------------------- /src/JsPlayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | class JsPlayer : public Napi::ObjectWrap 21 | { 22 | static Napi::FunctionReference _jsConstructor; 23 | 24 | public: 25 | static Napi::Object InitJsApi(Napi::Env env, Napi::Object exports); 26 | 27 | JsPlayer(const Napi::CallbackInfo&); 28 | ~JsPlayer(); 29 | 30 | private: 31 | enum AppSinkEvent { 32 | Setup = 0, 33 | NewPreroll, 34 | NewSample, 35 | Eos, 36 | }; 37 | 38 | void close(); 39 | 40 | bool parseLaunch(const std::string& pipelineDescription); 41 | 42 | bool addAppSinkCallback( 43 | const std::string& appSinkName, 44 | const Napi::Function& callback); 45 | 46 | bool addCapsProbe( 47 | const std::string& elementName, 48 | const std::string& padName, 49 | const Napi::Function& callback); 50 | 51 | void setState(unsigned state); 52 | 53 | void sendEos(); 54 | 55 | private: 56 | struct AppSinkData; 57 | 58 | void handleAsync(); 59 | 60 | void onSetup(AppSinkData*); 61 | 62 | void onSample( 63 | AppSinkData*, 64 | GstSample*, 65 | bool preroll); 66 | void onVideoSample( 67 | AppSinkData*, 68 | GstSample*, 69 | bool preroll); 70 | void onAudioSample( 71 | AppSinkData*, 72 | GstSample*, 73 | bool preroll); 74 | void onOtherSample( 75 | AppSinkData*, 76 | GstSample*, 77 | bool preroll); 78 | 79 | void onEos(GstAppSink*); 80 | 81 | void handleQueue(); 82 | void onCapsChanged(GstPad* pad, GstCaps* caps); 83 | void onEos(); 84 | 85 | void cleanup(); 86 | 87 | private: 88 | Napi::FunctionReference _eosCallback; 89 | 90 | GstElement* _pipeline; 91 | 92 | struct AppSinkData; 93 | std::map _appSinks; 94 | 95 | struct PadProbeData; 96 | std::map _padsProbes; 97 | 98 | uv_async_t* _queueAsync = nullptr; 99 | struct AsyncEvent; 100 | struct CapsChangedEvent; 101 | struct EosEvent; 102 | std::mutex _queueGuard; 103 | std::deque> _queue; 104 | 105 | uv_async_t* _async = nullptr; 106 | }; 107 | -------------------------------------------------------------------------------- /src/module.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "JsPlayer.h" 4 | 5 | 6 | Napi::Object Init(Napi::Env env, Napi::Object exports) 7 | { 8 | return JsPlayer::InitJsApi(env, exports); 9 | } 10 | 11 | NODE_API_MODULE(wcjs_gs, Init) 12 | --------------------------------------------------------------------------------