參考官網文章: https://dart.dev/guides/libraries/c-interop
1. 使用 linux 作業系統, 安裝好dart sdk , c 語言編譯程式加上 cmake
2. 新增一個 dart 專案, 專案內新增一個 hello 目錄 , 進入 hello 目錄, 準備要編譯成 hello 模組(libhello.so):
2.1 先在 hello 目錄裡面編輯一個檔案 CMakeLists.txt:
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
project(hello_library VERSION 1.0.0 LANGUAGES C)
add_library(hello_library SHARED hello.c hello.def)
add_executable(hello_test hello.c)
set_target_properties(hello_library PROPERTIES
PUBLIC_HEADER hello.h
VERSION ${PROJECT_VERSION}
SOVERSION 1
OUTPUT_NAME "hello"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Hex_Identity_ID_Goes_Here"
)
2.2. 為了指示要將函數(testWork, add, reverse 等等) 導出來(export)使用, 要編輯一個文字檔案 hello.def:
LIBRARY hello
EXPORTS
testWork
add
reverse
2.3. 編輯一個 c 程式,用來宣告函式原型的標頭檔 hello.h:
void testWork( );
int add(int a, double b);
char *reverse(char *str);
2.4. 編輯 c 模組程式的原始碼 hello.c:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "hello.h"
int main( ) {
testWork( );
printf("3 + 5 = %d\n", add(3, 5));
printf("%s\n",reverse("Hello-String") );
return 0;
}
void testWork( ) {
printf("It works!\n");
}
int add(int a, double b) {
return a + b;
}
char *_bufferPointer = NULL;
int _buffrLength = 0;
char *reverse(char *src) {
int size = strlen(src);
if(size == 0) return NULL;
else if(size > _buffrLength) { // allocate if space not enough
if(_bufferPointer != NULL) free(_bufferPointer);
_bufferPointer = (char *)malloc(size + 1);//from heap
_buffrLength = size;// maximum characters to hold
}
_bufferPointer[size] = '\0';// eos
for (int i = 0; i < size; i++) _bufferPointer[size - 1 - i] = src[i];// reverse
return _bufferPointer;
}
2.5 上述檔案都編輯完成後就能執行 make 作業, 製作成動態程式庫 (hello/libhello.so)
cmake .
make
3. 在專案內新增 pubspec.yaml 檔案, 完成後, 開啟終端機執行 pub get 準備使用 ffi:
name: cinterop
version: 0.0.1
description: >-
An example of calling C code from Dart through FFI
author: MyName<email@google.com>
environment:
sdk: '>=2.6.0 <3.0.0'
dependencies:
ffi: ^0.1.3
dev_dependencies:
test: ^1.5.3
4.編輯一個透過 ffi 界面呼叫 c 語言的 dart 範例程式 main.dart:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
main( ) {
final libso = DynamicLibrary.open('hello/libhello.so');
final testFun= libso.lookup<NativeFunction<Void Function( )>>('testWork').
asFunction<void Function()>();
final addFun = libso.lookup<NativeFunction<Int32 Function(Int32, Double)>>('add').
asFunction<int Function(int,double)>( );
final revFun = libso.lookup<NativeFunction<Pointer<Utf8> Function(Pointer<Utf8>)>>('reverse').
asFunction<Pointer<Utf8> Function(Pointer<Utf8>)>( );
final c2dartString = (Pointer<Utf8> _pointer) => Utf8.fromUtf8(_pointer);
final dartstring2c = (String _string) => Utf8.toUtf8(_string);
final reverse = (String _string) => c2dartString(revFun(dartstring2c(_string)));
testFun( );
print('adder: 334 + 5 = ${addFun(334, 5.0)}');
for(int i=0; i<20 ; i++) print('${reverse("$i.Hello-string")}');
}
5. 用 dart VM 執行上述 main.dart 看看: /pathToDartSDK/bin/dart main.dart
It works!
adder: 334 + 5 = 339
gnirts-olleH.0
gnirts-olleH.1
gnirts-olleH.2
gnirts-olleH.3
gnirts-olleH.4
gnirts-olleH.5
gnirts-olleH.6
gnirts-olleH.7
gnirts-olleH.8
gnirts-olleH.9
gnirts-olleH.01
gnirts-olleH.11
gnirts-olleH.21
gnirts-olleH.31
gnirts-olleH.41
gnirts-olleH.51
gnirts-olleH.61
gnirts-olleH.71
gnirts-olleH.81
gnirts-olleH.91
後記: dart SDK 的 dart2native 可以將原始碼轉成可執行檔, 不用 dart VM, 直接就能執行:
/pathToDartSDK/bin/dart2native main.dart && ./main.exe
2020年2月19日 星期三
2020年2月7日 星期五
Javascript 讀取 blob
Firefox 69 或是 Chrome 76 以後的版本, blob 透過擴展函數 arrayBuffer( ) 可以取得其中的內容, arrayBuffer( ) 可以用在像是透過 webSocket 取得的 blob 資料, 或是放入陣列中(_blobArray)再用 Blob 建構式產生的新 blob, 若是舊版本只能透過 FileReader 去讀取, 以下程式碼搭配 Promise 物件模擬 arrayBuffer 的讀取行為:
// arrayBuffer reader
async function blobReader(_blobArray) {
const blobTemp = new Blob(_blobArray);
if( blobTemp.arrayBuffer ) return await blobTemp.arrayBuffer( );
else { // use FileReader & Promise to read
var _ready = null;
const _arrayBuffer = new Promise((_resolv, _) => _ready=_resolv);
const _reader = new FileReader( );
_reader.onloadend = ( ) => _ready && _ready(_reader.result);
_reader.readAsArrayBuffer(blobTemp);
return await _arrayBuffer;
}
}
// arrayBuffer reader
async function blobReader(_blobArray) {
const blobTemp = new Blob(_blobArray);
if( blobTemp.arrayBuffer ) return await blobTemp.arrayBuffer( );
else { // use FileReader & Promise to read
var _ready = null;
const _arrayBuffer = new Promise((_resolv, _) => _ready=_resolv);
const _reader = new FileReader( );
_reader.onloadend = ( ) => _ready && _ready(_reader.result);
_reader.readAsArrayBuffer(blobTemp);
return await _arrayBuffer;
}
}
2020年2月5日 星期三
Javascript 使用 html5 的 MediaSource 播放器
Chrome 與 Firefox 都支援 HTML5 的 MediaSource, 但餵進去的資料必須是 fmp4 格式的資料結構, 伺服器可以透過 mp4fragment 將 mp4 檔案一一轉換成 fmp4 格式檔再傳給客戶端. 客戶端的播放程式(javascript)利用 html 的 video 標籤播放該影音檔, 將以下程式碼存成 html 文字檔, 放在伺服器讓客戶端(Chrome 或是 Firefox)來連線:
<html><head><meta charset='utf-8'></head><body><script>
const codec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
class HttpPlayer {
constructor (width, height) {
const video = document.createElement('video');
const mediaSource = new MediaSource( );
mediaSource.onsourceopen = _evt => {
var completeFile = null;
var number = 1; // total number to get
const sourceBuffer = mediaSource.addSourceBuffer(codec);
const httpGet = _filename => {
const url = `https://${location.origin.split("//").pop( )}${_filename}`;
const https = new XMLHttpRequest( );
https.responseType = 'arraybuffer';
https.onload = ( ) => sourceBuffer.appendBuffer(https.response);
https.onloadend = ( ) => completeFile = _duration => {
completeFile = null;
number -- <= 0 ? mediaSource.endOfStream( ) : (( ) => {
sourceBuffer.timestampOffset = _duration - 2;
httpGet("/streamN.fmp4"); // next fmp4
})( );
}
https.open('get', url);
https.send( );
}
sourceBuffer.onupdateend = _evt =>
completeFile && completeFile(mediaSource.duration);
httpGet("/stream0.fmp4"); // initial fmp4
}
video.width = width;
video.height = height;
video.muted = true;
video.controls = "controls";
video.autoplay = "autoplay";
video.src = URL.createObjectURL(mediaSource);
document.body.append(video);
}
};
new HttpPlayer(1024, 768);
</script></body></html>
<html><head><meta charset='utf-8'></head><body><script>
const codec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
class HttpPlayer {
constructor (width, height) {
const video = document.createElement('video');
const mediaSource = new MediaSource( );
mediaSource.onsourceopen = _evt => {
var completeFile = null;
var number = 1; // total number to get
const sourceBuffer = mediaSource.addSourceBuffer(codec);
const httpGet = _filename => {
const url = `https://${location.origin.split("//").pop( )}${_filename}`;
const https = new XMLHttpRequest( );
https.responseType = 'arraybuffer';
https.onload = ( ) => sourceBuffer.appendBuffer(https.response);
https.onloadend = ( ) => completeFile = _duration => {
completeFile = null;
number -- <= 0 ? mediaSource.endOfStream( ) : (( ) => {
sourceBuffer.timestampOffset = _duration - 2;
httpGet("/streamN.fmp4"); // next fmp4
})( );
}
https.open('get', url);
https.send( );
}
sourceBuffer.onupdateend = _evt =>
completeFile && completeFile(mediaSource.duration);
httpGet("/stream0.fmp4"); // initial fmp4
}
video.width = width;
video.height = height;
video.muted = true;
video.controls = "controls";
video.autoplay = "autoplay";
video.src = URL.createObjectURL(mediaSource);
document.body.append(video);
}
};
new HttpPlayer(1024, 768);
</script></body></html>
訂閱:
文章 (Atom)
Linux mint 玩 waydroid 一些心得
1. 目前使用 linux mint 22.1 作業系統可以順利跑起來, 可上官網去下載, 並安裝到硬碟. 2. 安裝 waydroid 可上網站 https://docs.waydro.id 參考看看: https://docs.waydro.id/usage/inst...
-
1. 上 Firebase 網站 註冊啟用 Firebase : https://firebase.google.com/ 2. 進入 Firebase Console 註冊開啟新專案 : https://console.firebase.google.com/...
-
Flutter 讓人很容易短時間就能開發出 app, 關鍵在於他開發了很多種小部件稱為 Widget, 將Widget 組合起來就是一個 app. 所謂 部 件(Widget)就是一個可以呈現在螢幕上的視覺系 物 件,幾乎可以說 Flutter 每個物件都是 部 件. 開發者透...