多媒体开发之cgo

这篇具有很好参考价值的文章主要介绍了多媒体开发之cgo。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

     go语言作为近十年来优秀的现代开发语言的代表,由于继承了c语言的简洁和很多现代语言的表达方式,在广泛的应用场景中得到众多爱好者的喜爱,如何将go和c、c++进行联合开发,拓展整个开发生态,不用重复造轮子,掌握cgo可以让你得心应手的在c和go之间传递信息,打通任督二脉。

    go在流媒体传输领域也有很强大的生态和优秀的轮子,比起传统的ffmpeg这种大而全的库,可以选择性的用一些小巧强悍的go语言写的库来替代ffmpeg,比如rtsp拉流,笔者用ffmpeg在android下写了一个推拉流的播放器,但是由于ffmpeg自成体系,在灵活定制方面有一些局限性,于是尝试用go rtsp来代替ffmpeg的rtsp拉流。

    首先我们需要利用cgo的交叉编译特性封装一个可以被c/c++调用的动态库,其中用到了cgo 进行设置和回调函数,并传递了类的指针,从而实现了c++ class的特性,达到了面向对象多路连接的设计目标。以下是go写的动态库源码,由于go的包管理做的特别棒,你可以用很少的代码实现一个多路拉流的应用。感觉比c++爽多了。

多媒体开发之cgo,图像智能,笔记,实时音视频,h.264,aac,rtsp

 多媒体开发之cgo,图像智能,笔记,实时音视频,h.264,aac,rtsp

 文章来源地址https://www.toymoban.com/news/detail-573188.html

package main

import (
	"fmt"
	"sync"
	"time"
	"unsafe"

	"github.com/deepch/vdk/av"
	"github.com/deepch/vdk/codec/h264parser"
	"github.com/deepch/vdk/format/rtsp"
)

/*
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#cgo CFLAGS: -I.
void OnSendPacket(void * callclass,unsigned char *data, int len,int mediatype);
typedef void (*CallbackFunc)(unsigned char *,int,int);
*/
import "C"

// 导出的回调函数类型
// type
// void SendcallbackFunc(unsigned char* data, int length);
// extern CallbackFunc _callback;
//
//	static void setCallbackWrapper(CallbackFunc callback) {
//	    _callback = callback;
//	}
type CallbackFunc func(*byte, int, int)

// 接口定义
type MediaInterface interface {
	SetCallback(callback CallbackFunc)
}

// 结构体实现接口
type MediaImplementation struct {
	id       int
	callback CallbackFunc
	// C._callback
	callclass unsafe.Pointer // 修改为unsafe.Pointer类型
}

var (
	instances     = make(map[int]*MediaImplementation)
	instancesLock sync.Mutex
	callbackLock  sync.Mutex
)

func (m *MediaImplementation) SendData(data []byte, length int, mediatype int) {
	// if C._callback != nil {
	fmt.Println("callback data len", length, mediatype)
	// arr := (*C.uchar)(unsafe.Pointer(&data[0]))
	// C.OnSendPacket(arr, C.int(length), C.int(mediatype))
}

func (m *MediaImplementation) CallBackData(data *byte, length int, mediatype int) {
	goSlice := (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length]
	m.SendData(goSlice, length, mediatype)
}

func (m *MediaImplementation) RtspClientStart(uri string) {
	// m.rtsp = unsafe.Pointer(&Rtspclient{
	// 	callback: m.CallBackData,
	// })
	// ((*Rtspclient)(m.rtsp)).rtspclient(uri)
	m.rtspConsumer(uri)
}

func (m *MediaImplementation) SetCallback(callback CallbackFunc) {
	m.callback = callback
}

//export CallRtspClientStart
func CallRtspClientStart(impl unsafe.Pointer, data *C.char) {
	if impl == nil {
		fmt.Println("Invalid implementation")
		return
	}
	m := (*MediaImplementation)(impl)
	m.rtspConsumer(C.GoString(data))
	// m.RtspClientStart(C.GoString(data))
}

//export NewMediaImplementation
func NewMediaImplementation() uintptr {
	instancesLock.Lock()
	defer instancesLock.Unlock()

	id := len(instances) + 1

	instance := &MediaImplementation{
		id: id,
	}

	instances[id] = instance

	return uintptr(unsafe.Pointer(instance))
}

//export GetMediaInstanceByID
func GetMediaInstanceByID(id C.int) uintptr { // 修改返回类型为uintptr
	instancesLock.Lock()
	defer instancesLock.Unlock()

	if instance, ok := instances[int(id)]; ok {
		return uintptr(unsafe.Pointer(instance))
	}

	return uintptr(0) // 返回表示未找到实例
}

//export CallSendData
func CallSendData(impl unsafe.Pointer, data *C.uchar, length C.int, mediatype C.int) {
	if impl == nil {
		fmt.Println("Invalid implementation")
		return
	}

	goSlice := (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length]
	m := (*MediaImplementation)(impl)
	go m.SendData(goSlice, int(length), int(mediatype))
}

//export SetCallbackWrapper
func SetCallbackWrapper(impl unsafe.Pointer, callback unsafe.Pointer) {
	if impl == nil {
		fmt.Println("Invalid implementation")
		return
	}
	m := (*MediaImplementation)(impl)
	m.callclass = callback
	fmt.Println("SetCallbackWrapper callback", m.callback, callback)
	// C._callback = callbackFunc
	// m.SetCallback(callbackFunc)
}

func main() {}

func (m *MediaImplementation) rtspConsumer(uri string) {
	annexbNALUStartCode := func() []byte { return []byte{0x00, 0x00, 0x00, 0x01} }
	//fmt.Println("rtspConsumer starting...")

	session, err := rtsp.DialTimeout(uri, 10*time.Second)
	// defer session.Close()
	if err != nil {
		fmt.Errorf("rtsp Dial Error: %v", err)
		return
		//panic(err)
	}

	//session.RtpKeepAliveTimeout = 10 * time.Second
	session.RtpTimeout = 20 * time.Second
	session.RtpKeepAliveTimeout = 5 * time.Second
	session.RtspTimeout = 20 * time.Second
	codecs, err := session.Streams()
	if err != nil {
		fmt.Errorf("stream error: %v", err)
		// continue
		//panic(err)
	}
	for i, t := range codecs {
		fmt.Printf("Stream", i, "is of type", t.Type().String())
	}

	if codecs[0].Type() != av.H264 {
		//fmt.Println("RTSP feed must begin with a H264 codec")
		// continue
		//panic("RTSP feed must begin with a H264 codec")
	}
	if len(codecs) != 1 {
		//fmt.Println("Ignoring all but the first stream.")
	}

	// var previousTime time.Duration
	for {
		// select {
		// case <-rtspsrcch:
		// default:
		// if KVMrtsp.BInUse != true {
		// 	break
		// }
		pkt, err := session.ReadPacket()
		if err != nil {
			break
		}

		// if pkt.Idx != 0 {
		// 	//audio or other stream, skip it
		// 	continue
		// }
		if codecs[pkt.Idx].Type().IsVideo() {
			pkt.Data = pkt.Data[4:]

			// For every key-frame pre-pend the SPS and PPS
			if pkt.IsKeyFrame {
				pkt.Data = append(annexbNALUStartCode(), pkt.Data...)
				pkt.Data = append(codecs[0].(h264parser.CodecData).PPS(), pkt.Data...)
				pkt.Data = append(annexbNALUStartCode(), pkt.Data...)
				pkt.Data = append(codecs[0].(h264parser.CodecData).SPS(), pkt.Data...)
				pkt.Data = append(annexbNALUStartCode(), pkt.Data...)
			} else {
				pkt.Data = append(annexbNALUStartCode(), pkt.Data...)
			}

			// bufferDuration := pkt.Time - previousTime
			// previousTime = pkt.Time
			// m.CallBackData(pkt.Data,len(pkt.Data))
			fmt.Println("Is Video IsKeyFrame", pkt.IsKeyFrame, codecs[pkt.Idx].Type(), pkt.Time)
			mediatype := 0
			switch codecs[pkt.Idx].Type() {
			case av.H264:
				mediatype = 1
			case av.H265:
				mediatype = 2
			}
			length := len(pkt.Data)
			arr := (*C.uchar)(unsafe.Pointer(&pkt.Data[0]))
			C.OnSendPacket(m.callclass, arr, C.int(length), C.int(mediatype))
			// if err = KVMrtsp.Track.WriteSample(media.Sample{Data: pkt.Data, Duration: bufferDuration}); err != nil && err != io.ErrClosedPipe {
			// 	logger.Errorf("WriteSample error %v", err)
			// 	break
			// 	//panic(err)
			// }
		} else if codecs[pkt.Idx].Type().IsAudio() {
			// codecs, err = session.Streams()
			// if err != nil {
			// 	fmt.Println("Error getting streams")
			// 	break
			// }
			codec := codecs[pkt.Idx].(av.AudioCodecData)
			duration, err := codec.PacketDuration(pkt.Data)
			if err != nil {
				fmt.Println("Failed to get duration for audio:", err)
				break
			}
			fmt.Println("IS Audio Packet duration:", duration)
			mediatype := 0
			switch codecs[pkt.Idx].Type() {
			case av.AAC:
				mediatype = 3
			case av.PCM_MULAW:
				mediatype = 4
			case av.PCM_ALAW:
				mediatype = 5
			case av.SPEEX:
				mediatype = 6
			case av.NELLYMOSER:
				mediatype = 7
			case av.PCM:
				mediatype = 8
			case av.OPUS:
				mediatype = 9
			}
			length := len(pkt.Data)
			arr := (*C.uchar)(unsafe.Pointer(&pkt.Data[0]))
			C.OnSendPacket(m.callclass, arr, C.int(length), C.int(mediatype))
			// m.CallBackData(pkt.Data,len(pkt.Data))
			// err = audioTrack.WriteSample(media.Sample{Data: pkt.Data, Duration: duration})
			// if err != nil {
			// 	//fmt.Println("Failed to write audio sample", err)
			// 	break
			// }
		}
	}

	if err = session.Close(); err != nil {
		fmt.Errorf("session Close error %v", err)
		return
	}

	// time.Sleep(5 * time.Second)

	// }
}

到了这里,关于多媒体开发之cgo的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 参会记录|全国多媒体取证暨第二届多媒体智能安全学术研讨会(MAS‘2023)

    前言 :2023年4月8日上午,我与实验室的诸位伙伴们共聚浙江杭州西子湖畔的六通宾馆,参加了为期一天半的全国多媒体取证暨第二届多媒体智能安全学术研讨会(MAS’2023)。本届学术研讨会由浙江省自然科学基金委员会资助,杭州电子科技大学承办。来自国内多媒体取证与

    2024年02月08日
    浏览(37)
  • 多媒体数据处理实验3:图像特征提取与检索

    1. 算法描述 功能:   使用BOF(Bag of Features)算法提取图像特征,在corel数据集(10*100)张图片上实现以图搜图,即输入数据集中某一张图,在剩下的999张图里搜索最邻近的10张图。 2.算法流程: 用 SIFT算法 提取图像的特征。每幅图像提取出几百至几千个特征点,将所有图像的特

    2024年02月07日
    浏览(46)
  • 多媒体库SDL以及实时音视频库WebRTC中的多线程问题实战详解

    目录 1、概述 2、开源跨平台多媒体库SDL介绍 3、开源音视频实时通信库WebRTC介绍

    2024年02月08日
    浏览(36)
  • (八)穿越多媒体奇境:探索Streamlit的图像、音频与视频魔法

    欢迎各位读者来到“最全Streamlit教程”专栏系列!如果您正在寻找一种简单而强大的方式来创建交互式数据应用程序,那么Streamlit无疑是您的最佳选择。作为该领域的热门框架,Streamlit让数据科学家、开发者和爱好者能够以前所未有的速度构建出引人入胜的数据可视化工具。

    2024年02月13日
    浏览(31)
  • [HTML]Web前端开发技术4(HTML5、CSS3、JavaScript )图像与多媒体文件hspace,vspace,scrollamount,bgcolor,marquee——喵喵画网页

    希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 图像与多媒体文件 网页文件常见的图像格式有: 图像 设置图像的替代文字 设置图像的宽度和高度

    2024年02月05日
    浏览(46)
  • HTML-多媒体嵌入-MDN文档学习笔记

    查看更多学习笔记:GitHub:LoveEmiliaForever MDN中文官网 将图片放入网页 可以使用 img/ 来将图片嵌入网页,它是一个空元素,最少只需 src 属性即可工作 src 指向图片资源的地址,是 img/ 正常工作必不可少的属性 ❗️除非有必要,否则 永远不要 把 src 指向其它网站上的图片,这

    2024年02月20日
    浏览(33)
  • 智能存储:多媒体实验室AIGC能力助力数据万象开启智能剪辑大门

    AIGC正从效率、质量、创意、多样性各方面革新内容生产流程,伴随firely、midjourney等现象级的产品出现,AIGC将逐步 广泛服务于内容生产的各类场景与内容生产者,随着AIGC在内容生产的需求场景不断增加,多媒体实验室也在AIGC领域持续发力,并通过数据万象将 能力成功应用到

    2024年02月10日
    浏览(35)
  • 鸿蒙HarmonyOS开发实战—多媒体开发(音频开发 一)

    HarmonyOS音频模块支持音频业务的开发,提供音频相关的功能,主要包括音频播放、音频采集、音量管理和短音播放等。 基本概念 采样 采样是指将连续时域上的模拟信号按照一定的时间间隔采样,获取到离散时域上离散信号的过程。 采样率 采样率为每秒从连续信号中提取并

    2024年01月24日
    浏览(36)
  • 读数据压缩入门笔记09_多媒体数据压缩

    4.6.1.1. 表示一个信号的最大可能功率与影响它的表示精度的破坏性噪声功率的比值(以对数分贝为单位) 4.6.1.2. 这一度量的基础是压缩图片的均方误差(mean-square error,MSE) 4.6.1.2.1. PSNR与MSE之间,存在着反比关系 4.6.1.3. 原始图像的值与压缩后的值差别有多大 4.6.2.1. 在比较

    2024年02月16日
    浏览(31)
  • Android多媒体功能开发(2)——FileProvider

    使用系统多媒体界面需要在我们的应用和其他应用之间通过Intent传递音频、图片、视频文件的信息。随着Android版本的升级,对应用数据安全性方面的限制越来越多。 Android 6以后不允许应用在外部存储随便创建目录,只能在Android规定的应用自己的文件目录下创建目录,该目录

    2024年02月14日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包