cgo 调用练习, 简单愚蠢命令行词典

在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 的高层插件, 提供媒体的播放功能, 它会自动建立媒体处理管线, 寻找合适的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 main

import (
    "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.WaitGroup

func  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.  [谷歌浏览器 铬,铬合金]

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 调用耗时越来越长。

时间: 2024-08-09 00:50:18

cgo 调用练习, 简单愚蠢命令行词典的相关文章

c#调用 WinRAR.exe以命令行形式实现文件、文件夹的解压缩

在实际项目应用中会偶尔使用文件的压缩上传以及服务器端的加压处理,故写此文记录以备不时之需. 1.自己编写的ZipHelper类. 1 public static class ZipHelper 2 { 3 private static string pathExe = AppDomain.CurrentDomain.BaseDirectory + @"Resource\WinRAR.exe"; 4 /// <summary> 5 /// 使用Gzip方法压缩文件 6 ///

简单的命令行选项

简单的命令行选项: import sys def main(): if len(sys.argv) != 3: print 'usage: ./wordcount.py {--count | --topcount} file' sys.exit(1) option = sys.argv[1] filename = sys.argv[2] if option == '--count': print_words(filename) elif option == '--topcount': print

lua学习笔记10:lua简单的命令行

前面反复使用的命令行,好学喜欢命令行: 一 格公式 lua [options][script][args] 两 详细命令 -e 直接命令传递一个lua -l 加载文件 -i 进入交互模式 比例如.端子输入: lua -e "print(math.sin(12))" 版权声明:本文博主原创文章,博客,未经同意不得转载.

最简单的命令行钉钉机器人发群信息

红色文字内容替换成自己的token,就可以通过命令行发布自己的钉钉群通知了 curl -H "Content-Type: application/json" -d '{"msgtype":"text","text":{"content":"我就是我, 是不一样的烟火"}}' https://oapi.dingtalk.com/robot/send?access_token=XXXXXXX

简单模仿命令行bash功能

用LINUX有一段时间了,一致在bash底下输入命令但是从来都很疑惑这个bash是如何知道我要输入的什么命令,于是用自己所学知识暂时模仿一些bash功能,后续继续完善功能. 第一次的版本: /********************************************************************** * Copyright (c)2015,WK Studios * Filename: main.c * Compiler: GCC,VS,VC6.0 win32 *

一个简单的命令行联系人程序 C++

用不准的英语写的说明,贴在github上. https://github.com/shalliestera/contacts/tree/master 这是头文件: #ifndef CCONTACTS_H_ #define CCONTACTS_H_ #include <map> #include <string> class CContacts { private: // map<std::string, std::string> std::map<std::str

使用百度翻译开放API构建的python命令行词典

不多说,上代码: 1 #!/usr/bin/python 2 #-*- encoding=utf-8 -*- 3 4 import urllib 5 import urllib2 6 import json 7 8 keys=raw_input('input you word > ') 9 10 args={'q':keys,'from':'en','to':'zh'} 11 12 encode_args=urllib.urlencode(args) 13 14 url='http://open

Ubuntu安装java的最简单的命令行方式

由于经常要安装java,因此 深受其烦! 分为两部: 1. sudo apt-get install openjdk-7-jdk 2. sudo vim /etc/environment 然后把下面的复制过去 : JAVA_HOME="/usr/lib/jvm/java-1.7.0-openjdk-amd64>" 3.source /etc/environment

FFmpeg命令行工具和批处理脚本进行简单的音视频文件编辑

FFmpeg_Tutorial FFmpeg工具和sdk库的使用demo 一.使用FFmpeg命令行工具和批处理脚本进行简单的音视频文件编辑 1.基本介绍 对于每一个从事音视频技术开发的工程师,想必没有一个人对FFmpeg这个名称感到陌生.FFmpeg是一套非常知名的音视频处理的开源工具,它包含了开发完成的工具软件.封装好的函数库以及源代码供我们按需使用.FFmpeg提供了非常强大的功能,可以完成音视频的编码.解码.转码.视频采集.后处理(抓图.水印.封装/解封装.格式转换等),还有流媒体服务等