0%

最近想從IP Camera和FFMpeg搭上陷,不過IP Cam走得不是標準的v4l2這套,只好另尋他路。
看了幾篇文章,時做了之後可以用,增添了自信心。
紀錄一下整個思路。

Step 1

仙分配一塊記憶體,當作IO Context的Buffer使用

1
2
const int iBufSize = 32 * 1024;
BYTE* pBuffer = new BYTE[iBufSize];

Step 2

向FFMpeg要求建立AVIOContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int ReadFunc(void* ptr, uint8_t* buf, int buf_size)
{
// Left to implement
}
int64_t SeekFunc(void* ptr, int64_t pos, int whence)
{
// Left to implement
}
AVIOContext* pIOCtx = avio_alloc_context(pBuffer, iBufSize, // internal Buffer and its size
0, // bWriteable (1=true,0=false)
pContext, // user data ; will be passed to our callback functions
ReadFunc,
0, // Write callback function (not used in this example)
SeekFunc);

上面的ReadFuncSeekFunc就代表Read和Seek的動作,而pContext就是有關的上下文,ReadFuncSeekFunc被呼叫時,pContext會被傳入ptr中。因此需要自行轉型成正確的上下文。

Step 3

建立AVFormatContex,這邊我是採用比較偷懶的作法,我已經知道InputFormat了,所以不需要Probe。如果要Probe可以參考Reference的連結。

1
2
3
4
AVFormatContext* pCtx = avformat_alloc_context();
pCtx->pb = pIOCtx;
pCtx->iformat = av_find_input_format("h264");
pCtx->flags = AVFMT_FLAG_CUSTOM_IO;

Step 4

依照FFMpeg正常的流程使用

1
2
if (avformat_open_input(&pCtx, "", 0, 0)) != 0)
// Error Handling

接著就跟一般無異了

Final

使用完後需要釋放資源

1
2
3
avformat_close_input(pCtx);  // AVFormatContext is released by avformat_close_input
av_free(pIOCtx); // AVIOContext is released by av_free
delete[] pBuffer;

Reference

又一個實驗性質的玩意,由於目前沒有IDE支持,一切從零開始。

一個簡單的範例

1
2
3
4
5
module Math;
export int add(int x, int y)
{
return x + y;
}

命名成add.ixx
接著main進來了

1
2
3
4
5
6
7
#include <stdio.h>
import Math;
int main()
{
printf("2 + 3 = %d\n", add(2, 3));
return 0;
}

以下是編譯過程

1
2
3
4
C:\> cl /c /experimental:module add.ixx
C:\> cl /experimental:module /module:reference Math.ifc main.cpp add.obj
C:\> main.exe
2 + 3 = 5

一切都看起來很美好
如果我們新增一個sub.ixx

1
2
3
4
5
module Math;
export int sub(int x, int y)
{
return x - y;
}

main也順勢改寫

1
2
3
4
5
6
int main()
{
printf("2 + 3 = %d\n", add(2, 3));
printf("3 - 2 = %d\n", sub(3, 2));
return 0;
}

這下子編譯救出錯了

1
2
3
4
5
C:\> cl /c /experimental:module add.ixx
C:\> cl /c /experimental:module sub.ixx
C:\> cl /experimental:module /module:reference Math.ifc main.cpp add.obj sub.obj
main.cpp
main.cpp(5): error C3861: 'add'

這個情況看起來Math.ifc被sub.ixx複寫了,以至於add的資訊消失。雖然可以用Module subdomain斃掉,不過這樣子很難用啊。

Template

試著在ixx當中放一些Template function,不過完全無效。還是只能放在Header file當中。

結論

有了Module之後,除了Template這種避不開的之外,Header file的重要性可能會大大降低 (再也不用擔心Winsock.h 跟 Windows.h的恩怨情仇了)。也能加速奇編譯速度。不過還在實驗階段,靜觀其變吧。

Visual C++ 2015提供了一個Coroutine的實驗性實作,未來可能會被列入C++17當中,因此先來體驗一下

Generator

這寫法就跟Python差不多了,直接用yield就行了
不過跟Javascript的Generator還是有一定程度的不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <experimental/generator>
using namespace std::experimental;
using namespace std;

generator<int> fib()
{
int a = 0;
int b = 1;
for (;;) {
yield a;
auto next = a + b;
a = b;
b = next;
}
}

int main(int argc, char* argv[])
{
for (auto v : fib()) {
if (v > 50)
break;
cout << v << endl;
}
}

async function

以下是個示範程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <future>
#include <iostream>
using namespace std;
using namespace std::chrono;

// this could be some long running computation or I/O
future<int> calculate_the_answer()
{
return async([] {
this_thread::sleep_for(1s); return 42;
});
}

// Here is a resumable function
future<void> coro() {
cout << this_thread::get_id() << " Started waiting... \n";
auto result = await calculate_the_answer();
cout << this_thread::get_id() << " : woke up, get " << result << endl;
}

int main(int argc, char* argv[])
{
coro().get();
cout << this_thread::get_id() << ": back in main\n";
}

future<void>await的語法實在是有點突兀(尤其是其他語言都用asyncawait之後)
如果我們拿掉await會造成怎樣的結果

1
2
3
4
5
6
7
8
9
10
11
void noncoro() {
cout << this_thread::get_id() << " Started waiting... \n";
auto result = calculate_the_answer().get();
cout << this_thread::get_id() << " : woke up, get " << result << endl;
}

int main(int argc, char* argv[])
{
noncoro();
cout << this_thread::get_id() << ": back in main\n";
}

可以看到兩個函數的不同

  • coro: Main Thread Invoke calculate_the_answer -> Child Thread Return
  • noncoro: Main Thread Invoke calculate_the_answer -> Main Thread Return

Complex Example

這個範例有點複雜,有時間在研究吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <windows.h>
#include <future>
#include <iostream>
#include <experimental/resumable>
using namespace std;
using namespace std::chrono;
using namespace std::experimental;

auto operator await(system_clock::duration duration) {
class awaiter {
static void CALLBACK TimerCallback(PTP_CALLBACK_INSTANCE, void *Context, PTP_TIMER) {
coroutine_handle<>::from_address(Context)();
}
PTP_TIMER timer = nullptr;
system_clock::duration duration;
public:
explicit awaiter(system_clock::duration d) : duration(d) {}
bool await_ready() const { return duration.count() <= 0; }
bool await_suspend(coroutine_handle<> resume_cb) {
int64_t relative_count = -duration.count();
timer = CreateThreadpoolTimer(TimerCallback, resume_cb.to_address(), nullptr);
SetThreadpoolTimer(timer, (PFILETIME)&relative_count, 0, 0);
return timer != 0;
}
void await_resume() {}
~awaiter() { if (timer) CloseThreadpoolTimer(timer); }
};
return awaiter{ duration };
}

future<void> test() {
cout << this_thread::get_id() << ": sleeping...\n";
await 1s;
cout << this_thread::get_id() << ": woke up\n";
}

int main() {
test().get();
cout << this_thread::get_id() << ": back in main\n";
}

Reference

Resumable functions in C++
Coroutines in Visual Studio 2015 - Update 1
Stackless coroutines with Visual Studio 2015

1
2
3
4
5
6
7
8
template <typename T>
struct has_member_foo
{
template <typename U, void (U::*)()> struct SFINAE {};
template <typename U> static char check(SFINAE<U, &U::foo>*);
template <typename U> static int check(...);
static const bool value = sizeof(check<T>(0)) == sizeof(char);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <utility>
template <typename T>
struct has_member_foo11
{
private:
template<typename U> static auto check(int) ->
decltype(std::declval<U>().foo(), std::true_type());

template<typename U> static std::false_type check(...);

public:
enum {
value = std::is_same<decltype(check<T>(0)),std::true_type>::value
};
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename T, typename ...Args>
struct has_member_foo11
{
private:
template<typename U> static auto check(int) ->
decltype(std::declval<U>().foo(std::declval<Args>()...), std::true_type());

template<typename U> static std::false_type check(...);

public:
enum {
value = std::is_same<decltype(check<T>(0)),std::true_type>::value
};
};

由於Ubuntu自帶的NodeJS版本實在太舊了,只好自行安裝,動手跑一遍流程,記錄下來。目前的NodeJS還無法完全支援ES6,所以還需要Babel之類的轉成ES5執行。

使用NVM安裝NodeJS

1
2
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash
$ nvm install stable

安裝Babel

1
$ npm i -g babel-cli

First Project

1
2
3
$ mkdir test && cd test
$ npm init
$ vim test.js

以下是測試程式,用到了ES6的let和ES7的asyncawait等Feature。

1
2
3
4
5
6
7
8
9
10
11
12
function sleep(ms = 0) {
return new Promise((resolve, reject) => setTimeout(resolve, ms));
}

async function test() {
for (let i = 0; i < 10; i++) {
await sleep(500);
console.log(`i = ${i}`);
}
}

test().then(() => console.log('done'));

執行的時候遇到困難

1
2
3
4
5
6
7
8
9
$ babel-node test.js
SyntaxError: /test/test.js: Unexpected token (5:6)
3 | }
4 |
> 5 | async function test() {
| ^
6 | for (let i = 0; i < 10; i++) {
7 | await sleep(500);
8 | console.log(`i = ${i}`);

因為Babel沒辦法正確的轉譯ES7語法

Problem Solving

1
$ npm i babel-preset-es2015 babel-preset-stage-0 --save-dev

在目前目錄上新增.babelrc`

1
2
3
{
"presets": ["es2015", "stage-0"]
}

這樣程式就能漲常執行。

Compile to ES5

當然,可能還有跑在Browser的需求,因此轉成ES5還是必須的。

1
2
3
4
5
6
7
8
9
10
11
12
$ babel test.js --out-file test.compiled.js
$ node test.compiled.js
/test/test.compiled.js:14
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {

ReferenceError: regeneratorRuntime is not defined
at /test/test.compiled.js:14:31
``
還是遇到問題。
#### Problem Solving
~~~bash
$ npm i babel-polyfill --save-dev

在est.compile.js爭最前面加上

1
require("babel-polyfill");
1
$ node  test.compiled.js

這下正常了

Problem

夜路走多了總是會碰到鬼,講述一下遇到的情形
我們有兩個Shared library,liba.solibb.so
內容類似如此

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
void inner()
{
printf("inner in a\n");
}
void outer_a()
{
printf("outer in a\n");
inner();
}

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
void inner()
{
printf("inner in b\n");
}
void outer_b()
{
printf("outer in b\n");
inner();
}

如果有個程式這樣寫

1
2
3
4
5
6
7
void outer_a();
void outer_b();
int main()
{
outer_a();
outer_b();
}

當我們編譯這個程式

1
2
$ gcc main.c liba.so libb.so -o main
$ LD_LIBRARY_PATH=./ ./main

結果匯出呼常理預料之外ㄝ,取決於Linking順序,跟我們想要的結果不同。

Simple Solution

將其中一個inner function加上static即可。如

1
2
3
4
static void inner()
{
printf("inner in b\n");
}

這樣結果就可以正常運作了,不過不適用於C++ Member Function之類的,我遇到的情形不是用這種寫法。

Best Solution (Hidden Visibility)

跟上面的方法類似,只需要將其中之一的inner隱藏寢來不可見就行了,將需要的Function輸出

1
2
3
4
5
6
7
8
9
10
11
#define EXPORTED __attribute__((visibility("default")))
#include <stdio.h>
void inner()
{
printf("inner in b\n");
}
EXPORTED void outer_b()
{
printf("outer in b\n");
inner();
}

編譯的時候就選擇

1
$ gcc -fPIC -shared -fvisibility=hidden b.c -o libb.so

就可以達成想要的結果了

Reference

how to link with two shared libraries with many conflicting functions

我只是個Javascript初新者,寫出來的可能也會務人子弟。
只是對Javascript的Asynchronous Programming Model有興趣,紀錄一下。

Callback Hell

在最初的Javascript的設計,程式只能這樣寫。一層又一層的Callback。不蛋難以維護,並且容易出錯。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function wait(func, val) {
return setTimeout(() => {
func(val);
}, 1000);
}
function asyncTask() {
var val = 0;
wait((val) => {
console.log("Step 1");
console.log(val);
wait((val) => {
console.log("Step 2");
console.log(val);
wait((val) => {
console.log("Step 3");
console.log(val);
wait((val) => {
console.log("Finish");
console.log(val);
}, val + 4);
}, val + 3);
}, val + 2);
}, val + 1);
}

asyncTask();

ES6之後引季Promise,可以將Callback從水平拓展變成垂直拓展,讓程式碼更像是一般Synchronous Programming的方式

Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
function wait(func, val) {
return setTimeout(() => {
func(val);
}, 1000);
}
function finish(val) {
console.log("Finish");
console.log(val);
}
function step3(val) {
console.log("Step 3");
console.log(val);
}
function step2(val) {
console.log("Step 2");
console.log(val);
}
function step1(val) {
console.log("Step 1");
console.log(val);
}
function waitPromise(func, val) {
return new Promise((resolve, reject) => {
wait(() => {
func(val);
resolve(val);
});
});
}
function asyncTask() {
var val = 0;
return waitPromise(step1, val + 1).then((val) => {
return waitPromise(step2, val + 2);
}).then((val) => {
return waitPromise(step3, val + 3);
}).then((val) => {
return waitPromise(finish, val + 4);
});
}

asyncTask();


asyncTask();

Generator

不過ES6同樣引入了Generator,可以用Generator模擬Synchronous Programming的方式
asyncTaskFlow是個Generator就是控制流,只是我們要以這個順序執行
比起Promise更像是我們熟悉的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function wait(func) {
return setTimeout(func, 1000);
}
function finish() {
console.log("Finish");
}
function step3() {
console.log("Step 3");
}
function step2() {
console.log("Step 2");
}
function step1() {
console.log("Step 1");
}
function* asyncTaskFlow() {
yield wait(step1);
yield wait(step2);
yield wait(step3);
yield wait(finish);
}
function asyncTask() {
var gen = asyncTaskFlow();
for (v of gen) ;
}

asyncTask();

Async & Await

跟C#一樣,用Async和Awit作為最終解決方案,雖然這還處在ES7 Draft,不過日後應該會被採用
可以參考 ES7 async functionsSimplifying Asynchronous Coding with ES7 Async Functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
async function finish(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Finish");
resolve(val + 4);
});
});
}
async function step3(val ) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 3");
resolve(val + 3);
});
});
}
async function step2(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 2");
resolve(val + 2);
});
});
}
async function step1(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 1");
resolve(val + 1);
});
});
}
async function asyncTask() {
var result = await step1(0);;
console.log(result);
result = await step2(result);
console.log(result);
result = await step3(result);
console.log(result);
result = await finish(result);
console.log(result);
}
asyncTask();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function wait(func) {
return setTimeout(func, 1000);
}
async function finish(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Finish");
resolve(val + 4);
});
});
}
async function step3(val ) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 3 failed");
reject("Cancel operation");
});
});
}
async function step2(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 2");
resolve(val + 2);
});
});
}
async function step1(val) {
return new Promise((resolve, reject) => {
wait(() => {
console.log("Step 1");
resolve(val + 1);
});
});
}
async function asyncTask() {
try {
var result = await step1(0);;
console.log(result);
result = await step2(result);
console.log(result);
result = await step3(result);
console.log(result);
result = await finish(result);
console.log(result);
} catch (err) {
console.log(err);
}
}
asyncTask();

有時候想要在Linux的Terminal想要印出彩色字串方便,可以有以下方法

C Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
};

int main (int argc, char const *argv[]) {

printf(ANSI_COLOR_RED "This text is RED!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_GREEN "This text is GREEN!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_YELLOW "This text is YELLOW!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_BLUE "This text is BLUE!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_MAGENTA "This text is MAGENTA!" ANSI_COLOR_RESET "\n");
printf(ANSI_COLOR_CYAN "This text is CYAN!" ANSI_COLOR_RESET "\n");
return 0;
}

這方法簡單,不過麻煩的是要手動加上Color跟Reset標籤在文字前後。

C++11 Solution

突然想到可以用C++11的新特性User defined literal來簡化,可以減少不少手動置入的風險。也可以練習User defined literal的如何使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <string>
namespace {
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"


#define DEFINE_COLOR_STRING(color) \
std::string operator"" _##color (const char* str) \
{ \
std::string tmp(ANSI_COLOR_##color); \
tmp += str; \
tmp += ANSI_COLOR_RESET; \
return tmp;\
}
DEFINE_COLOR_STRING(RED);
DEFINE_COLOR_STRING(GREEN);
DEFINE_COLOR_STRING(YELLOW);
DEFINE_COLOR_STRING(BLUE);
DEFINE_COLOR_STRING(MAGENTA);
DEFINE_COLOR_STRING(CYAN);
};
std::cout << 123_RED << 456_YELLOW << 789_BLUE << std::endl;

不過User Defined Literal前的字串似乎不能寫成”123 456”_RED這種形式。有點可惜

```

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T, std::size_t N>
class ArrayResult {
constexpr static std::size_t size_ = N;
T data_[N] {};
public:
constexpr std::size_t size() const { return N; }
constexpr T& operator[](std::size_t n) { return data_[n]; }
constexpr const T& operator[](std::size_t n) const { return data_[n]; }
using iterator = T*;
using const_iterator = const T*;
constexpr iterator begin() { return &data_[0]; }
constexpr const_iterator begin() const { return &data_[0]; }
constexpr iterator end() { return &data_[N]; }
constexpr const_iterator end() const { return &data_[N]; }
};

好久沒寫文章了,把之前看到的資料記一記。馬有失蹄,人有錯手,在怎麼宣告不用Debugger的Programming language,可能也需要gdb搭配使用,這邊紀錄一下如何用gdb來幫助golan除錯。
範例程式

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"
)

func main() {
for i := 0; i < 5; i++ {
fmt.Println("Loop")
}
fmt.Println("Done")
}

編譯時間入debuu info

1
$ go build -gcflags "-N -l" test.go

積著就可以照

1
2
$ gdb test
$ b main.main

之後就能夠像之前一樣使用gdb了

Reference

Debugging Go Code with GDB
– [Debugging Go (golang) programs with gdb ]http://thornydev.blogspot.tw/2014/01/debugging-go-golang-programs-with-gdb.html)
Introduction to Go Debugging with GDB
Using the gdb debugger with Go