deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
10
dev-packages/ffmpeg/.eslintrc.js
Normal file
10
dev-packages/ffmpeg/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: [
|
||||
'../../configs/build.eslintrc.json'
|
||||
],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: 'tsconfig.json'
|
||||
}
|
||||
};
|
||||
3
dev-packages/ffmpeg/README.md
Normal file
3
dev-packages/ffmpeg/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# `ffmeg.node`
|
||||
|
||||
This is a [Node Native Addon](https://nodejs.org/docs/latest-v14.x/api/n-api.html) to dynamically link to Electron's `ffmpeg.dll` and fetch a list of included codecs.
|
||||
29
dev-packages/ffmpeg/binding.gyp
Normal file
29
dev-packages/ffmpeg/binding.gyp
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
'targets': [{
|
||||
'defines': ['NAPI_VERSION=2'],
|
||||
'target_name': 'ffmpeg',
|
||||
'sources': [
|
||||
'native/ffmpeg.c',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="linux"', {
|
||||
'sources': [
|
||||
'native/linux-ffmpeg.c',
|
||||
],
|
||||
'libraries': [
|
||||
'-ldl',
|
||||
]
|
||||
}],
|
||||
['OS=="mac"', {
|
||||
'sources': [
|
||||
'native/mac-ffmpeg.c',
|
||||
]
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'sources': [
|
||||
'native/win-ffmpeg.c',
|
||||
]
|
||||
}],
|
||||
],
|
||||
}],
|
||||
}
|
||||
146
dev-packages/ffmpeg/native/ffmpeg.c
Normal file
146
dev-packages/ffmpeg/native/ffmpeg.c
Normal file
@@ -0,0 +1,146 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2019 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
/**
|
||||
* https://nodejs.org/docs/latest-v10.x/api/n-api.html#n_api_n_api
|
||||
*/
|
||||
#include <node_api.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ffmpeg.h"
|
||||
|
||||
/**
|
||||
* Return the list of codecs registered in the FFMPEG library.
|
||||
*/
|
||||
napi_value codecs(napi_env env, napi_callback_info info)
|
||||
{
|
||||
// We will reuse this `status` for all napi calls.
|
||||
napi_status status;
|
||||
char *error = NULL;
|
||||
|
||||
// Get arguments.
|
||||
size_t argc = 1;
|
||||
napi_value argv[1];
|
||||
status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
|
||||
if (status != napi_ok || argc < 1)
|
||||
{
|
||||
error = "invalid arguments";
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Get first argument as string.
|
||||
char path[2048];
|
||||
status = napi_get_value_string_utf8(env, argv[0], path, 2048, NULL);
|
||||
if (status != napi_ok)
|
||||
{
|
||||
error = "invalid string argument";
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Load ffmpeg based on the provided path.
|
||||
struct FFMPEG_Library ffmpeg = NULL_FFMPEG_LIBRARY;
|
||||
char *load_error = load_ffmpeg_library(&ffmpeg, path);
|
||||
if (load_error != NULL)
|
||||
{
|
||||
error = load_error;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Create the JavaScript list that will be returned.
|
||||
napi_value codecs;
|
||||
status = napi_create_array(env, &codecs);
|
||||
if (status != napi_ok)
|
||||
{
|
||||
error = "napi_create_array fail";
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Iterate over the codec descriptions.
|
||||
// It includes descriptions for codecs that may not be present in the library.
|
||||
struct AVCodecDescriptor *descriptor = ffmpeg.avcodec_descriptor_next(NULL);
|
||||
while (descriptor != NULL)
|
||||
{
|
||||
// Try to fetch the codec being described, returns null on missing codecs.
|
||||
struct AVCodec *decoder = ffmpeg.avcodec_find_decoder(descriptor->id);
|
||||
if (decoder != NULL)
|
||||
{
|
||||
// Create the codec object and assign the properties.
|
||||
napi_value object, value;
|
||||
napi_create_object(env, &object);
|
||||
|
||||
// id: number
|
||||
napi_create_int32(env, decoder->id, &value);
|
||||
napi_set_named_property(env, object, "id", value);
|
||||
|
||||
// name: string
|
||||
napi_create_string_utf8(env, decoder->name, strlen(decoder->name), &value);
|
||||
napi_set_named_property(env, object, "name", value);
|
||||
|
||||
// longName: string
|
||||
napi_create_string_utf8(env, decoder->long_name, strlen(decoder->long_name), &value);
|
||||
napi_set_named_property(env, object, "longName", value);
|
||||
|
||||
// Pushing into a JS array requires calling the JS method for that.
|
||||
napi_value push_fn;
|
||||
napi_get_named_property(env, codecs, "push", &push_fn);
|
||||
napi_call_function(env, codecs, push_fn, 1, (napi_value[]){object}, NULL);
|
||||
}
|
||||
descriptor = ffmpeg.avcodec_descriptor_next(descriptor);
|
||||
}
|
||||
|
||||
// Free the ffmpeg library.
|
||||
char *unload_error = unload_ffmpeg_library(&ffmpeg);
|
||||
if (unload_error != NULL)
|
||||
{
|
||||
error = unload_error;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return codecs;
|
||||
|
||||
error:
|
||||
if (error != NULL)
|
||||
{
|
||||
napi_throw_error(env, NULL, error);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://nodejs.org/docs/latest-v10.x/api/n-api.html#n_api_module_registration
|
||||
*/
|
||||
napi_value initialize(napi_env env, napi_value exports)
|
||||
{
|
||||
napi_status status;
|
||||
napi_value function_codecs;
|
||||
|
||||
status = napi_create_function(env, NULL, 0, codecs, NULL, &function_codecs);
|
||||
if (status != napi_ok)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = napi_set_named_property(env, exports, "codecs", function_codecs);
|
||||
if (status != napi_ok)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
NAPI_MODULE(NODE_GYP_MODULE_NAME, initialize);
|
||||
80
dev-packages/ffmpeg/native/ffmpeg.h
Normal file
80
dev-packages/ffmpeg/native/ffmpeg.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef FFMPEG_H
|
||||
#define FFMPEG_H
|
||||
/**
|
||||
* THIS FILE REDEFINES DATA AS RETURNED BY THE FFMPEG LIBRARY.
|
||||
* HEADER FILES ARE NOT DISTRIBUTED IN OUR SETUP, HENCE THIS.
|
||||
*/
|
||||
|
||||
/**
|
||||
* https://github.com/FFmpeg/FFmpeg/blob/release/3.2/libavutil/avutil.h#L193-L201
|
||||
*/
|
||||
enum AVMediaType
|
||||
{
|
||||
_UNKNOWN_DATA_AVMediaType = -1,
|
||||
};
|
||||
|
||||
/**
|
||||
* https://github.com/FFmpeg/FFmpeg/blob/release/3.2/libavcodec/avcodec.h#L191-L653
|
||||
*/
|
||||
enum AVCodecID
|
||||
{
|
||||
__UNKNOWN_DATA_AVCodecID = 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* https://github.com/FFmpeg/FFmpeg/blob/release/3.2/libavcodec/avcodec.h#L3611-L3721
|
||||
*/
|
||||
struct AVCodec
|
||||
{
|
||||
const char *name, *long_name;
|
||||
enum AVMediaType type;
|
||||
enum AVCodecID id;
|
||||
};
|
||||
|
||||
/**
|
||||
* https://github.com/FFmpeg/FFmpeg/blob/release/3.2/libavcodec/avcodec.h#L660-L688
|
||||
*/
|
||||
struct AVCodecDescriptor
|
||||
{
|
||||
enum AVCodecID id;
|
||||
enum AVMediaType type;
|
||||
const char *name, *long_name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper around the ffmpeg library that must be loaded at runtime.
|
||||
*/
|
||||
struct FFMPEG_Library
|
||||
{
|
||||
void *handle;
|
||||
|
||||
/**
|
||||
* https://github.com/FFmpeg/FFmpeg/blob/release/3.2/libavcodec/avcodec.h#L6228
|
||||
*
|
||||
* We use AVCodecDescriptor because it is the only structure that we can
|
||||
* query on all platforms. Windows' ffmpeg.dll does not export a
|
||||
* `av_codec_next` function, only `avcodec_descriptor_next`.
|
||||
* Also it seems that this "descriptor" concept is the recommended API.
|
||||
*/
|
||||
struct AVCodecDescriptor *(*avcodec_descriptor_next)(const struct AVCodecDescriptor *);
|
||||
|
||||
/**
|
||||
* https://github.com/FFmpeg/FFmpeg/blob/release/3.2/libavcodec/avcodec.h#L4646
|
||||
*/
|
||||
struct AVCodec *(*avcodec_find_decoder)(enum AVCodecID);
|
||||
};
|
||||
|
||||
#define NULL_FFMPEG_LIBRARY \
|
||||
(struct FFMPEG_Library) { NULL, NULL, NULL }
|
||||
|
||||
/**
|
||||
* Loader that will inject the loaded functions into a FFMPEG_Library structure.
|
||||
*/
|
||||
char *load_ffmpeg_library(struct FFMPEG_Library *library, char *library_path);
|
||||
|
||||
/**
|
||||
* Free library.
|
||||
*/
|
||||
char *unload_ffmpeg_library(struct FFMPEG_Library *library);
|
||||
|
||||
#endif // FFMPEG_H guard
|
||||
68
dev-packages/ffmpeg/native/linux-ffmpeg.c
Normal file
68
dev-packages/ffmpeg/native/linux-ffmpeg.c
Normal file
@@ -0,0 +1,68 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2019 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
#ifndef LINUX_FFMPEG
|
||||
#define LINUX_FFMPEG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "ffmpeg.h"
|
||||
|
||||
char *load_ffmpeg_library(struct FFMPEG_Library *library, char *library_path)
|
||||
{
|
||||
void *handle = dlopen(library_path, RTLD_NOW);
|
||||
char *error = dlerror();
|
||||
if (error != NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct AVCodecDescriptor *(*avcodec_descriptor_next)(const struct AVCodecDescriptor *) = dlsym(handle, "avcodec_descriptor_next");
|
||||
error = dlerror();
|
||||
if (error != NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct AVCodec *(*avcodec_find_decoder)(enum AVCodecID) = dlsym(handle, "avcodec_find_decoder");
|
||||
error = dlerror();
|
||||
if (error != NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
library->handle = handle;
|
||||
library->avcodec_descriptor_next = avcodec_descriptor_next;
|
||||
library->avcodec_find_decoder = avcodec_find_decoder;
|
||||
return NULL;
|
||||
|
||||
error:
|
||||
if (handle != NULL)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
char *unload_ffmpeg_library(struct FFMPEG_Library *library)
|
||||
{
|
||||
dlclose(library->handle);
|
||||
*library = NULL_FFMPEG_LIBRARY;
|
||||
return dlerror();
|
||||
}
|
||||
|
||||
#endif // LINUX_FFMPEG guard
|
||||
26
dev-packages/ffmpeg/native/mac-ffmpeg.c
Normal file
26
dev-packages/ffmpeg/native/mac-ffmpeg.c
Normal file
@@ -0,0 +1,26 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2019 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
#ifndef MAC_FFMPEG
|
||||
#define MAC_FFMPEG
|
||||
|
||||
/**
|
||||
* Mac seems to use the same libraries as Linux.
|
||||
* Difference is that the compiler doesn't need to be told to use `-ldl`.
|
||||
*/
|
||||
#include "./linux-ffmpeg.c"
|
||||
|
||||
#endif // MAC_FFMPEG guard
|
||||
77
dev-packages/ffmpeg/native/win-ffmpeg.c
Normal file
77
dev-packages/ffmpeg/native/win-ffmpeg.c
Normal file
@@ -0,0 +1,77 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2019 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
#ifndef WIN_FFMPEG
|
||||
#define WIN_FFMPEG
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "ffmpeg.h"
|
||||
|
||||
static char *error_library_not_found = "shared library not found";
|
||||
static char *error_function_not_found = "function not found in shared library";
|
||||
static char *error_cannot_free_library = "cannot free shared library";
|
||||
|
||||
char *load_ffmpeg_library(struct FFMPEG_Library *library, char *library_path)
|
||||
{
|
||||
char *error = NULL;
|
||||
|
||||
HMODULE handle = LoadLibrary(library_path);
|
||||
if (!handle)
|
||||
{
|
||||
error = error_library_not_found;
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct AVCodecDescriptor *(*av_codec_next)(const struct AVCodecDescriptor *) = (struct AVCodecDescriptor * (*)(const struct AVCodecDescriptor *))
|
||||
GetProcAddress(handle, "avcodec_descriptor_next");
|
||||
if (!av_codec_next)
|
||||
{
|
||||
error = error_function_not_found;
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct AVCodec *(*avcodec_find_decoder)(enum AVCodecID) = (struct AVCodec * (*)(enum AVCodecID))
|
||||
GetProcAddress(handle, "avcodec_find_decoder");
|
||||
if (!avcodec_find_decoder)
|
||||
{
|
||||
error = error_function_not_found;
|
||||
goto error;
|
||||
}
|
||||
|
||||
library->handle = handle;
|
||||
library->avcodec_descriptor_next = av_codec_next;
|
||||
library->avcodec_find_decoder = avcodec_find_decoder;
|
||||
return NULL;
|
||||
|
||||
error:
|
||||
if (handle)
|
||||
{
|
||||
FreeLibrary(handle);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
char *unload_ffmpeg_library(struct FFMPEG_Library *library)
|
||||
{
|
||||
if (library->handle && FreeLibrary(library->handle))
|
||||
{
|
||||
*library = NULL_FFMPEG_LIBRARY;
|
||||
return NULL;
|
||||
}
|
||||
return error_cannot_free_library;
|
||||
}
|
||||
|
||||
#endif // WIN_FFMPEG guard
|
||||
40
dev-packages/ffmpeg/package.json
Normal file
40
dev-packages/ffmpeg/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@theia/ffmpeg",
|
||||
"version": "1.68.0",
|
||||
"description": "Theia FFMPEG reader utility.",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/eclipse-theia/theia.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/eclipse-theia/theia/issues"
|
||||
},
|
||||
"homepage": "https://github.com/eclipse-theia/theia",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"binding.gyp",
|
||||
"lib",
|
||||
"native",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"compile": "theiaext compile",
|
||||
"lint": "theiaext lint",
|
||||
"build": "theiaext build",
|
||||
"watch": "theiaext watch",
|
||||
"clean": "theiaext clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/get": "^2.0.0",
|
||||
"tslib": "^2.6.2",
|
||||
"unzipper": "^0.9.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/unzipper": "^0.9.2"
|
||||
},
|
||||
"gitHead": "21358137e41342742707f660b8e222f940a27652"
|
||||
}
|
||||
56
dev-packages/ffmpeg/src/check-ffmpeg.ts
Normal file
56
dev-packages/ffmpeg/src/check-ffmpeg.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2019 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import * as ffmpeg from './ffmpeg';
|
||||
|
||||
export interface CheckFfmpegOptions extends ffmpeg.FfmpegOptions {
|
||||
json?: boolean
|
||||
}
|
||||
|
||||
export interface CheckFfmpegResult {
|
||||
free: ffmpeg.Codec[],
|
||||
proprietary: ffmpeg.Codec[],
|
||||
}
|
||||
|
||||
export const KNOWN_PROPRIETARY_CODECS = new Set(['h264', 'aac']);
|
||||
|
||||
export async function checkFfmpeg(options: CheckFfmpegOptions = {}): Promise<void> {
|
||||
const {
|
||||
ffmpegPath = ffmpeg.ffmpegAbsolutePath(options),
|
||||
json = false,
|
||||
} = options;
|
||||
const codecs = ffmpeg.getFfmpegCodecs(ffmpegPath);
|
||||
const free = [];
|
||||
const proprietary = [];
|
||||
for (const codec of codecs) {
|
||||
if (KNOWN_PROPRIETARY_CODECS.has(codec.name.toLowerCase())) {
|
||||
proprietary.push(codec);
|
||||
} else {
|
||||
free.push(codec);
|
||||
}
|
||||
}
|
||||
if (json) {
|
||||
// Pretty format JSON on stdout.
|
||||
const result: CheckFfmpegResult = { free, proprietary };
|
||||
console.log(JSON.stringify(result, undefined, 2));
|
||||
}
|
||||
if (proprietary.length > 0) {
|
||||
// Should be displayed on stderr to not pollute the JSON on stdout.
|
||||
throw new Error(`${proprietary.length} proprietary codecs found\n${proprietary.map(codec => `> ${codec.name} detected (${codec.longName})`).join('\n')}`);
|
||||
}
|
||||
// Print to stderr to not pollute the JSON on stdout.
|
||||
console.warn(`"${ffmpegPath}" does not contain proprietary codecs (${codecs.length} found).`);
|
||||
}
|
||||
114
dev-packages/ffmpeg/src/ffmpeg.ts
Normal file
114
dev-packages/ffmpeg/src/ffmpeg.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2019 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import path = require('path');
|
||||
|
||||
export interface Codec {
|
||||
id: number
|
||||
name: string
|
||||
longName: string
|
||||
}
|
||||
|
||||
export interface FfmpegNativeAddon {
|
||||
codecs(ffmpegPath: string): Codec[]
|
||||
}
|
||||
|
||||
export interface FfmpegNameAndLocation {
|
||||
/**
|
||||
* Name with extension of the shared library.
|
||||
*/
|
||||
name: string
|
||||
/**
|
||||
* Relative location of the file from Electron's dist root.
|
||||
*/
|
||||
location: string
|
||||
}
|
||||
|
||||
export interface FfmpegOptions {
|
||||
electronVersion?: string
|
||||
electronDist?: string
|
||||
ffmpegPath?: string
|
||||
platform?: NodeJS.Platform
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function _loadFfmpegNativeAddon(): FfmpegNativeAddon {
|
||||
try {
|
||||
return require('../build/Release/ffmpeg.node');
|
||||
} catch (error) {
|
||||
if (error.code === 'MODULE_NOT_FOUND') {
|
||||
return require('../build/Debug/ffmpeg.node');
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns name and relative path from Electron's root where FFMPEG is located at.
|
||||
*/
|
||||
export function ffmpegNameAndLocation({
|
||||
platform = process.platform
|
||||
}: FfmpegOptions = {}): FfmpegNameAndLocation {
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
return {
|
||||
name: 'libffmpeg.dylib',
|
||||
location: 'Electron.app/Contents/Frameworks/Electron Framework.framework/Libraries/',
|
||||
};
|
||||
case 'win32':
|
||||
return {
|
||||
name: 'ffmpeg.dll',
|
||||
location: '',
|
||||
};
|
||||
case 'linux':
|
||||
return {
|
||||
name: 'libffmpeg.so',
|
||||
location: '',
|
||||
};
|
||||
default:
|
||||
throw new Error(`${platform} is not supported`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns relative ffmpeg shared library path from the Electron distribution root.
|
||||
*/
|
||||
export function ffmpegRelativePath(options: FfmpegOptions = {}): string {
|
||||
const { location, name } = ffmpegNameAndLocation(options);
|
||||
return path.join(location, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns absolute ffmpeg shared library path.
|
||||
*/
|
||||
export function ffmpegAbsolutePath(options: FfmpegOptions = {}): string {
|
||||
const {
|
||||
electronDist = path.resolve(require.resolve('electron/package.json'), '..', 'dist')
|
||||
} = options;
|
||||
return path.join(electronDist, ffmpegRelativePath(options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically link to `ffmpegPath` and use FFMPEG APIs to list the included `Codec`s.
|
||||
* @param ffmpegPath absolute path the the FFMPEG shared library.
|
||||
* @returns list of codecs for the given ffmpeg shared library.
|
||||
*/
|
||||
export function getFfmpegCodecs(ffmpegPath: string): Codec[] {
|
||||
return _loadFfmpegNativeAddon().codecs(ffmpegPath);
|
||||
}
|
||||
28
dev-packages/ffmpeg/src/hash.ts
Normal file
28
dev-packages/ffmpeg/src/hash.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2021 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import crypto = require('crypto');
|
||||
import fs = require('fs-extra');
|
||||
|
||||
export async function hashFile(filePath: string): Promise<Buffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const sha256 = crypto.createHash('sha256');
|
||||
fs.createReadStream(filePath)
|
||||
.on('close', () => resolve(sha256.digest()))
|
||||
.on('data', data => sha256.update(data))
|
||||
.on('error', reject);
|
||||
});
|
||||
}
|
||||
20
dev-packages/ffmpeg/src/index.ts
Normal file
20
dev-packages/ffmpeg/src/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2021 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
export * from './hash';
|
||||
export * from './ffmpeg';
|
||||
export * from './check-ffmpeg';
|
||||
export * from './replace-ffmpeg';
|
||||
80
dev-packages/ffmpeg/src/replace-ffmpeg.ts
Normal file
80
dev-packages/ffmpeg/src/replace-ffmpeg.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2019 Ericsson and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import electronGet = require('@electron/get');
|
||||
import fs = require('fs-extra');
|
||||
import os = require('os');
|
||||
import path = require('path');
|
||||
import unzipper = require('unzipper');
|
||||
import * as ffmpeg from './ffmpeg';
|
||||
import { hashFile } from './hash';
|
||||
|
||||
export async function replaceFfmpeg(options: ffmpeg.FfmpegOptions = {}): Promise<void> {
|
||||
let shouldDownload = true;
|
||||
let shouldReplace = true;
|
||||
const {
|
||||
name: ffmpegName,
|
||||
location: ffmpegLocation,
|
||||
} = ffmpeg.ffmpegNameAndLocation(options);
|
||||
const {
|
||||
electronDist = path.resolve(require.resolve('electron/package.json'), '..', 'dist'),
|
||||
electronVersion = await readElectronVersion(electronDist),
|
||||
ffmpegPath = path.resolve(electronDist, ffmpegLocation, ffmpegName),
|
||||
} = options;
|
||||
const ffmpegCachedPath = path.join(os.tmpdir(), `theia-cli/cache/electron-v${electronVersion}`, ffmpegName);
|
||||
if (await fs.pathExists(ffmpegCachedPath)) {
|
||||
shouldDownload = false; // If the file is already cached, do not download.
|
||||
console.warn('Found cached ffmpeg library.');
|
||||
const [cacheHash, distHash] = await Promise.all([
|
||||
hashFile(ffmpegCachedPath),
|
||||
hashFile(ffmpegPath),
|
||||
]);
|
||||
if (cacheHash.equals(distHash)) {
|
||||
shouldReplace = false; // If files are already the same, do not replace.
|
||||
console.warn('Hashes are equal, not replacing the ffmpeg library.');
|
||||
}
|
||||
}
|
||||
if (shouldDownload) {
|
||||
const ffmpegZipPath = await electronGet.downloadArtifact({
|
||||
version: electronVersion,
|
||||
artifactName: 'ffmpeg'
|
||||
});
|
||||
const ffmpegZip = await unzipper.Open.file(ffmpegZipPath);
|
||||
const file = ffmpegZip.files.find(f => f.path.endsWith(ffmpegName));
|
||||
if (!file) {
|
||||
throw new Error(`Archive did not contain "${ffmpegName}".`);
|
||||
}
|
||||
// Extract file to cache.
|
||||
await fs.mkdirp(path.dirname(ffmpegCachedPath));
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
file.stream()
|
||||
.pipe(fs.createWriteStream(ffmpegCachedPath))
|
||||
.on('finish', resolve)
|
||||
.on('error', reject);
|
||||
});
|
||||
console.warn(`Downloaded ffmpeg shared library { version: "${electronVersion}", dist: "${electronDist}" }.`);
|
||||
}
|
||||
if (shouldReplace) {
|
||||
await fs.copy(ffmpegCachedPath, ffmpegPath);
|
||||
console.warn(`Successfully replaced "${ffmpegPath}".`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function readElectronVersion(electronDist: string): Promise<string> {
|
||||
const electronVersionFilePath = path.resolve(electronDist, 'version');
|
||||
const version = await fs.readFile(electronVersionFilePath, 'utf8');
|
||||
return version.trim();
|
||||
}
|
||||
12
dev-packages/ffmpeg/tsconfig.json
Normal file
12
dev-packages/ffmpeg/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../../configs/base.tsconfig",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": []
|
||||
}
|
||||
Reference in New Issue
Block a user