這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
在go 的程式中調用 c 代碼, golang 提供了兩種方法: cgo, swing 。gstreamer 是開源跨平台的多媒體架構庫,主要是在gnome 基礎核心庫 glib 之上構建。下面有一個簡單的使用cgo 封裝 gstreamer playbin 外掛程式的例子: gstuse.go
package main/*#cgo pkg-config: gstreamer-1.0#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <gst/gst.h>void play(const char *uri){ GstElement *pipeline; GstBus *bus; GstMessage *msg; gst_init (NULL, NULL); char *res; if (-1 == asprintf(&res, "playbin uri=%s", uri)){ return; } pipeline = gst_parse_launch(res, NULL); if(!pipeline){ g_print("create playbin pipeline error\n"); free(res); return; } gst_element_set_state (pipeline, GST_STATE_PLAYING); bus = gst_element_get_bus (pipeline); msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR|GST_MESSAGE_EOS); if (msg != NULL) gst_message_unref (msg); free(res); gst_object_unref (bus); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline);}*/import "C"import "unsafe"func sndply(snd string){ if snd == ""{ return } cs := C.CString(snd) defer C.free(unsafe.Pointer(cs)) C.play(cs)}
把c 代碼寫在注釋之中,很像python/c 之間的 cffi 工具, #cgo 是cgo 工具的編譯指示標誌, pkg-config 指定所需連結的庫的元資訊, 標頭檔,庫位置等,
如果是平時跟c 代碼連結 一般這樣使用 pkg-config --cflags --libs gstreamer-1.0, cgo 中只需要寫庫名字 。playbin 是gstreamer 的高層外掛程式, 提供媒體的播放功能, 它會自動建立ApsaraVideo for Media Processing管線, 尋找合適的demuxer, decoder。
gst_parse_launch() 函數, 提供類似gst-lanch-×xx 命令列工具文法組建處理pipeline。 使用
gst_element_set_state
把pipeline 設定為啟動播放狀態,然後擷取pipeline的匯流排, 在匯流排上等待直到遇到錯誤,或者媒體流的末尾。
C.CString 把 golang string 類型轉換*C.char , 其是在heap 上分配, 需要調用C.free 釋放。下面是使用金山詞霸api 的例子:
gciba.go
package mainimport ( "fmt" "log" "flag" "sync" "net/http" "net/url" "encoding/json")const reqUri = "http://dict-co.iciba.com/api/dictionary.php?"type Dict struct { Exchange struct { Word_done string `json:"word_done"` Word_er []string `json:"word_er"` Word_est []string `json:"word_est"` Word_ing string `json:"word_ing"` Word_past string `json:"word_past"` Word_pl []string `json:"word_pl"` Word_third string `json:"word_third"` }`json:"exchange"` Iscri int `json:"is_CRI"` Items []string `json:"items"` Symbols []struct{ Parts []struct{ Means []string `json:"means"` Part string `json:"part"` }`json:"parts"` Ph_am string `json:"ph_am"` Ph_am_mp3 string `json:"ph_am_mp3"` Ph_en string `json:"ph_en"` Ph_en_mp3 string `json:"ph_en_mp3"` Ph_other string `json:"ph_other"` Ph_tts_mp3 string `json:"ph_tts_mp3"` }`json:"symbols"` Word_name string `json:"word_name"`}func player(snds chan string, done chan bool){ for s := range snds { sndply(s) } close(done)}func doTrans(word string, snds chan string) { defer wg.Done() reqArgs := url.Values{} reqArgs.Add("w", word) reqArgs.Add("type", "json") reqArgs.Add("key", "E9E58402D44342EFB0B1ABC41E86BF8E") resp, err := http.Get(reqUri + reqArgs.Encode()) if err != nil { log.Println(err) return } defer resp.Body.Close() var res Dict enc := json.NewDecoder(resp.Body) enc.Decode(&res) //fmt.Println(res) var snd string if len(res.Symbols) < 1 { return } switch *phonetic { case "am": snd = res.Symbols[0].Ph_am_mp3 case "en": snd = res.Symbols[0].Ph_en_mp3 default : snd = res.Symbols[0].Ph_tts_mp3 } snds <- snd fmt.Printf("am: %s, en: %s\n", res.Symbols[0].Ph_am, res.Symbols[0].Ph_en ) for _, p := range res.Symbols[0].Parts { fmt.Printf("%s %s\n", p.Part, p.Means) } fmt.Println()}var phonetic = flag.String("phon", "am", "use american or english phonetic")var wg sync.WaitGroupfunc main() { flag.Parse() snds := make(chan string, flag.NArg()) done := make(chan bool) go player(snds, done) for _, w := range flag.Args(){ wg.Add(1) go doTrans(w, snds) } wg.Wait() close(snds) <-done}
player 函數包裹了gstuse.go 中的 sndply ,使用單獨的goroutine 調用 player函數,player 從 snds channel 讀取聲音uri,直到channel 被關閉,close done channel, 通知main goroutine, 自己要退出。doTrans 發起web request, 解析包含json的結果,提取聲音uri 發到 snds channel。snds 是緩衝channel,也可改成無緩衝channel, 使得上一個單詞未發音之前,不得列印下一個單詞。
編譯 : go build -o gciba gciba.go gstuse.go
./gciba clear some thing chrome
am: kroʊm, en: krəʊm
n. [Google瀏覽器 鉻,鉻合金]
vt. [鍍以鉻 用鉻化合物印染]
am: θɪŋ, en: θɪŋ
n. [事件,形勢 東西,事物 傢伙 事業]
am: sʌm, en: səm
adj. [一些 某個 大約 相當多的]
pron. [一些 若干 其中的一部分 (數量不確切時用)有些人]
adv. [非常 相當 <美>稍微]
am: klɪr, en: klɪə(r)
adj. [清楚的,明白的 清晰的,明亮的 清澈的 明確的]
adv. [完全地 清晰地 整整]
vi. [變明朗 變清澈]
vt. [掃除,除去 消除(嫌疑) 使清楚 使乾淨]
n. [空隙,空間]
cgo 調用也存在以些問題,由於所調用的c 庫由於設計上的問題, 使用 thread local storage或者某些api 不是thread safe ,導致不能並發使用,或者要鎖在特定線程之上。 minux 指出從 golang1.0 到 1.4 cgo 調用耗時越來越長。