{"id":7616,"date":"2021-06-01T12:16:13","date_gmt":"2021-06-01T04:16:13","guid":{"rendered":"https:\/\/kyle.ai\/blog\/?p=7616"},"modified":"2021-06-01T14:33:39","modified_gmt":"2021-06-01T06:33:39","slug":"%e9%80%9a%e8%bf%87-cgo-%e5%ae%9e%e7%8e%b0-vobsub2pgm-%e5%8a%9f%e8%83%bd","status":"publish","type":"post","link":"https:\/\/kyle.ai\/blog\/7616.html","title":{"rendered":"\u901a\u8fc7 cgo \u5b9e\u73b0 vobsub2pgm \u529f\u80fd"},"content":{"rendered":"<p>\u672c\u6587\u4e3b\u8981\u5b9e\u73b0\u7f16\u5199 go \u8bed\u8a00\u4ee3\u7801\uff0c\u53bb\u8c03\u7528 mplayer \u7684 c \u8bed\u8a00\u4ee3\u7801\uff0c\u5c06 .sub \u5b57\u5e55\u6587\u4ef6\u8f6c\u6210 .pgm \u683c\u5f0f\u7684\u56fe\u7247\u6587\u4ef6\u3002<\/p>\n<p>\u76f8\u5f53\u4e8e\u4f7f\u7528 go \u6765\u6539\u5199 <a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/github.com\/ruediger\/VobSub2SRT\/blob\/master\/src\/vobsub2srt.c%2B%2B\">\u8fd9\u4e2a\u4ee3\u7801<\/a> \u3002<\/p>\n<p><code>vobsub.go<\/code> \u5185\u5bb9\u5982\u4e0b\uff1a<\/p>\n<pre><code class=\"language-go \">package main\n\n\/\/ mplayer \u4ee3\u7801\u6765\u6e90\u4e8e https:\/\/github.com\/ruediger\/VobSub2SRT\/tree\/master\/mplayer\n\/\/ \u8fd9\u4e2a\u6587\u4ef6\u76f8\u5f53\u4e8e\u7528 go \u6539\u5199\u793a\u4f8b VobSub2SRT\/src\/vobsub2srt.c++\n\n\/*\n#include &lt;vobsub.h&gt;\n#include &lt;stdlib.h&gt;\n#include &lt;spudec.h&gt;\n#include &lt;mp_msg.h&gt;\n*\/\nimport \"C\"\nimport (\n    \"flag\"\n    \"fmt\"\n    \"os\"\n    \"path\/filepath\"\n    \"strings\"\n    \"unsafe\"\n)\n\nvar subBaseNmae = flag.String(\"subName\", \"\", \"\u8f93\u5165 .sub \u5b57\u5e55\u6587\u4ef6\u8def\u5f84\uff0c\u9700\u8981\u53bb\u6389 .sub \u548c .idx \u6587\u4ef6\u540e\u7f00\")\n\nfunc main() {\n    flag.Parse()\n    if strings.TrimSpace(*subBaseNmae) == \"\" {\n        println(\"Please enter subfile\")\n        os.Exit(1)\n    }\n    \/\/ C \u4e2d\u7684 void * \u5bf9\u5e94 cgo \u4e2d\u7684 unsafe.Pointer\n    var spu unsafe.Pointer\n    \/\/ \u8c03\u7528 C.free \u65f6\u786e\u4fdd\u8981\u5f15\u7528 include &lt;stdlib.h&gt;\n    defer C.free(spu)\n    \/\/ void mp_msg_init(void);\n    C.mp_msg_init()\n    subBaseDir, _ := filepath.Abs(filepath.Dir(*subBaseNmae))\n    \/\/ char * \u5bf9\u5e94 cgo \u4e2d\u7684 C.CString\n    subname := C.CString(*subBaseNmae)\n    \/\/ \u5bf9\u7533\u8bf7\u7684\u975e go \u7c7b\u578b\uff0c\u90fd\u8981\u624b\u52a8\u8fdb\u884c\u56de\u6536\n    defer C.free(unsafe.Pointer(subname))\n\n    \/\/ void *vobsub_open(const char *subname, const char *const ifo, const int force, unsigned int y_threshold, void** spu);\n    \/\/ void** \u5bf9\u5e94 cgo \u4e2d\u76f4\u63a5\u53d6 unsafe.Pointer \u5730\u5740\uff0c\u5373 &amp;spu\n    vob := C.vobsub_open(subname, C.CString(\"\"), C.int(1), C.uint(0), &amp;spu)\n    defer C.free(vob)\n\n    var packet unsafe.Pointer\n    defer C.free(packet)\n\n    var timestamp, vlen C.int\n    var lastStartPts, width, height, stride, startPts, endPts C.uint\n    minWidth := 9\n    minHeight := 1\n    subCounter := 1\n\n    var image *C.uchar\n    defer C.free(unsafe.Pointer(image))\n    var imageSize C.size_t\n\n    for {\n        \/\/ int vobsub_get_packet(void *vobhandle, float pts, void** data, int* timestamp);\n        vlen = C.vobsub_get_next_packet(vob, &amp;packet, &amp;timestamp)\n        if vlen &lt;= 0 {\n            break\n        }\n        if timestamp &lt; 0 {\n            continue\n        }\n        \/\/ void spudec_assemble(void *self, unsigned char *packet, unsigned int len, int pts100);\n        \/\/ \u5c06 unsafe.Pointer \u7c7b\u578b\u7684 packet \u8f6c\u6210 unsigned char * --&gt; (*C.uchar)(packet)\n        C.spudec_assemble(spu, (*C.uchar)(packet), C.uint(vlen), timestamp)\n        \/\/ void spudec_heartbeat(void *self, unsigned int pts100);\n        C.spudec_heartbeat(spu, C.uint(timestamp))\n\n        \/\/ void spudec_get_data(void *self, const unsigned char **image, size_t *image_size, unsigned *width, unsigned *height,\n        \/\/  unsigned *stride, unsigned *start_pts, unsigned *end_pts);\n        \/\/ image \u4e0a\u6307\u5411 C.uchar \u7684\u6307\u9488\uff0c\u6240\u4ee5 unsigned char **image \u5c31\u53ea\u9700\u8981\u5bf9 image \u53d6\u5730\u5740\u64cd\u4f5c\n        C.spudec_get_data(spu, &amp;image, &amp;imageSize, &amp;width, &amp;height, &amp;stride, &amp;startPts, &amp;endPts)\n        if startPts == lastStartPts {\n            continue\n        }\n        lastStartPts = startPts\n        if int(width) &lt; minWidth || int(height) &lt; minHeight {\n            continue\n        }\n\n        \/\/ \u8fd9\u91cc\u5982\u4f55\u5c06 *C.uchar \u8f6c\u6210 go \u7684 []bytes\n        gobytes := C.GoBytes(unsafe.Pointer(image), C.int(imageSize))\n\n        fname := fmt.Sprintf(\"pgm_%d.pgm\", subCounter)\n        fpath := filepath.Join(subBaseDir, fname)\n        f, _ := os.Create(fpath)\n        f.Write([]byte(fmt.Sprintf(\"P5\\n%d %d %d\\n\", int(width), int(height), 255)))\n        f.Write(gobytes)\n\n        f.Close()\n        subCounter++\n    }\n}\n\n<\/code><\/pre>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/kyle.ai\/blog\/wp-content\/uploads\/2021\/06\/vobsub.zip\">\u6e90\u4ee3\u7801<\/a><\/p>\n<p>\u53c2\u8003\u94fe\u63a5\uff1a<\/p>\n<ul>\n<li>https:\/\/karthikkaranth.me\/blog\/calling-c-code-from-go\/<\/li>\n<li>http:\/\/litang.me\/post\/golang-cgo\/<\/li>\n<li>https:\/\/golang.org\/cmd\/cgo\/<\/li>\n<li>https:\/\/jamesadam.me\/2016\/03\/26\/c-and-go-dealing-with-void-parameters-in-cgo\/<\/li>\n<li>https:\/\/github.com\/golang\/go\/wiki\/cgo<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>\u672c\u6587\u4e3b\u8981\u5b9e\u73b0\u7f16\u5199 go \u8bed\u8a00\u4ee3\u7801\uff0c\u53bb\u8c03\u7528 mplayer \u7684 c \u8bed\u8a00\u4ee3\u7801\uff0c\u5c06 .sub \u5b57\u5e55\u6587\u4ef6\u8f6c\u6210 .pg [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-7616","post","type-post","status-publish","format-standard","hentry","category-diary"],"_links":{"self":[{"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/posts\/7616","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/comments?post=7616"}],"version-history":[{"count":3,"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/posts\/7616\/revisions"}],"predecessor-version":[{"id":7620,"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/posts\/7616\/revisions\/7620"}],"wp:attachment":[{"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/media?parent=7616"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/categories?post=7616"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kyle.ai\/blog\/wp-json\/wp\/v2\/tags?post=7616"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}