Merged in gardening/simplify (pull request #53)

rtmp: simplify rtmp code and make more type-safe

Approved-by: Saxon Milton <saxon.milton@gmail.com>
This commit is contained in:
kortschak 2018-09-09 23:32:44 +00:00
commit 3f8082d52e
6 changed files with 632 additions and 1109 deletions

View File

@ -39,6 +39,7 @@ package rtmp
import "C"
import (
"encoding/binary"
"log"
"unsafe"
)
@ -91,26 +92,22 @@ func C_AMF_DecodeInt32(data *byte) uint32 {
// void AMF_DecodeString(const char* data, C_AVal* bv);
// amf.c +68
func C_AMF_DecodeString(data *byte, bv *C_AVal) {
dataPtr := unsafe.Pointer(data)
//bv.av_len = int32(C.AMF_DecodeInt16((*byte)(dataPtr)))
bv.av_len = int32(C_AMF_DecodeInt16((*byte)(dataPtr)))
if bv.av_len > 0 {
bv.av_val = (*byte)(incBytePtr(dataPtr, 2))
} else {
bv.av_val = nil
func C_AMF_DecodeString(data *byte) string {
n := C_AMF_DecodeInt16(data)
if n == 0 {
return ""
}
return string((*[_Gi]byte)(incBytePtr(unsafe.Pointer(data), 2))[:n])
}
// void AMF_DecodeLongString(const char *data, AVal *bv);
// amf.c +75
func C_AMF_DecodeLongString(data *byte, bv *C_AVal) {
bv.av_len = int32(C_AMF_DecodeInt32(data))
if bv.av_len > 0 {
bv.av_val = (*byte)(incBytePtr(unsafe.Pointer(data), 4))
} else {
bv.av_val = nil
func C_AMF_DecodeLongString(data *byte) string {
n := C_AMF_DecodeInt32(data)
if n == 0 {
return ""
}
return string((*[_Gi]byte)(incBytePtr(unsafe.Pointer(data), 4))[:n])
}
// double AMF_DecodeNumber(const char* data);
@ -128,11 +125,8 @@ func C_AMF_DecodeNumber(data *byte) float64 {
// int AMF_DecodeBoolean(const char *data);
// amf.c +132
func C_AMF_DecodeBoolean(data *byte) int32 {
if *data != 0 {
return 1
}
return 0
func C_AMF_DecodeBoolean(data *byte) bool {
return *data != 0
}
// char* AMF_EncodeInt16(char* output, char* outend, short nVal);
@ -197,33 +191,27 @@ func C_AMF_EncodeInt32(output *byte, outend *byte, nVal int32) *byte {
// char* AMF_EncodeString(char* output, char* outend, const C_AVal* bv);
// amf.c +174
func C_AMF_EncodeString(output *byte, outend *byte, bv *C_AVal) *byte {
outputPtr := unsafe.Pointer(output)
outendPtr := unsafe.Pointer(outend)
if (bv.av_len < 65536 && uintptr(incBytePtr(outputPtr, 1+2+int(bv.av_len))) >
uintptr(outendPtr)) || uintptr(incBytePtr(outputPtr, 1+4+int(bv.av_len))) >
uintptr(outendPtr) {
func C_AMF_EncodeString(output *byte, outend *byte, s string) *byte {
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
if len(s) < 65536 && 1+2+len(s) > buflen {
return nil
}
if bv.av_len < 65536 {
*(*byte)(outputPtr) = AMF_STRING
outputPtr = incBytePtr(outputPtr, 1)
// TODO: port AMF_EncodeInt16
outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr), (*byte)(
outendPtr), int16(bv.av_len)))
//outputPtr = unsafe.Pointer(C_AMF_EncodeInt16((*byte)(outputPtr),
//(*byte)(outendPtr), (int16)(bv.av_len)))
} else {
*(*byte)(outputPtr) = AMF_LONG_STRING
outputPtr = incBytePtr(outputPtr, 1)
outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr), (*byte)(
outendPtr), int32(bv.av_len)))
//outputPtr = unsafe.Pointer(C_AMF_EncodeInt32((*byte)(outputPtr),
//(*byte)(outendPtr), (int32)(bv.av_len)))
if 1+4+len(s) > buflen {
return nil
}
outputPtr := unsafe.Pointer(output)
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
if len(s) < 65536 {
dst[0] = AMF_STRING
binary.BigEndian.PutUint16(dst[1:3], uint16(len(s)))
copy(dst[3:], s)
outputPtr = incBytePtr(outputPtr, 3+len(s))
} else {
dst[0] = AMF_LONG_STRING
binary.BigEndian.PutUint32(dst[1:5], uint32(len(s)))
copy(dst[5:], s)
outputPtr = incBytePtr(outputPtr, 5+len(s))
}
memmove(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), uintptr(bv.av_len))
//C.memcpy(unsafe.Pointer(outputPtr), unsafe.Pointer(bv.av_val), (C.size_t)(bv.av_len))
outputPtr = incBytePtr(outputPtr, int(bv.av_len))
return (*byte)(outputPtr)
}
@ -249,15 +237,15 @@ func C_AMF_EncodeNumber(output *byte, outend *byte, dVal float64) *byte {
// char* AMF_EncodeBoolean(char* output, char* outend, int bVal);
// amf.c +260
func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal int) *byte {
func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal bool) *byte {
if int(uintptr(unsafe.Pointer(output)))+2 > int(uintptr(unsafe.Pointer(outend))) {
return nil
}
*(*byte)(unsafe.Pointer(output)) = AMF_BOOLEAN
output = (*byte)(incBytePtr(unsafe.Pointer(output), 1))
val := byte(0x01)
if bVal == 0 {
val = byte(0x00)
var val byte
if bVal {
val = 1
}
*(*byte)(unsafe.Pointer(output)) = val
output = (*byte)(incBytePtr(unsafe.Pointer(output), 1))
@ -266,44 +254,50 @@ func C_AMF_EncodeBoolean(output *byte, outend *byte, bVal int) *byte {
// char* AMF_EncodeNamedString(char* output, char* outend, const C_AVal* strName, const C_AVal* strValue);
// amf.c +273
func C_AMF_EncodeNamedString(output *byte, outend *byte, strName *C_AVal, strValue *C_AVal) *byte {
if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) {
func C_AMF_EncodeNamedString(output *byte, outend *byte, key, val string) *byte {
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
if 2+len(key) > buflen {
return nil
}
output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len))
memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len))
output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len)))
return C_AMF_EncodeString(output, outend, strValue)
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
copy(dst[2:], key)
output = (*byte)(incBytePtr(unsafe.Pointer(output), 2+len(key)))
return C_AMF_EncodeString(output, outend, val)
}
// char* AMF_EncodeNamedNumber(char* output, char* outend, const C_AVal* strName, double dVal);
// amf.c +286
func C_AMF_EncodeNamedNumber(output *byte, outend *byte, strName *C_AVal, dVal float64) *byte {
if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) {
func C_AMF_EncodeNamedNumber(output *byte, outend *byte, key string, val float64) *byte {
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
if 2+len(key) > buflen {
return nil
}
output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len))
memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len))
output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len)))
return C_AMF_EncodeNumber(output, outend, dVal)
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
copy(dst[2:], key)
output = (*byte)(incBytePtr(unsafe.Pointer(output), 2+len(key)))
return C_AMF_EncodeNumber(output, outend, val)
}
// char* AMF_EncodeNamedBoolean(char* output, char* outend, const C_AVal* strname, int bVal);
// amf.c +299
func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, strName *C_AVal, bVal int) *byte {
if int(uintptr(unsafe.Pointer(output)))+2+int(strName.av_len) > int(uintptr(unsafe.Pointer(outend))) {
func C_AMF_EncodeNamedBoolean(output *byte, outend *byte, key string, val bool) *byte {
buflen := int(uintptr(unsafe.Pointer(outend)) - uintptr(unsafe.Pointer(output)))
if 2+len(key) > buflen {
return nil
}
output = C_AMF_EncodeInt16(output, outend, int16(strName.av_len))
memmove(unsafe.Pointer(output), unsafe.Pointer(strName.av_val), uintptr(strName.av_len))
output = (*byte)(incBytePtr(unsafe.Pointer(output), int(strName.av_len)))
return C_AMF_EncodeBoolean(output, outend, bVal)
dst := (*[_Gi]byte)(unsafe.Pointer(output))[:buflen]
binary.BigEndian.PutUint16(dst[:2], uint16(len(key)))
copy(dst[2:], key)
output = (*byte)(incBytePtr(unsafe.Pointer(output), 2+len(key)))
return C_AMF_EncodeBoolean(output, outend, val)
}
// void AMFProp_SetName(AMFObjectProperty *prop, AVal *name);
// amf.c +318
func C_AMFProp_SetName(prop *C_AMFObjectProperty, name *C_AVal) {
prop.p_name = *name
func C_AMFProp_SetName(prop *C_AMFObjectProperty, name string) {
prop.p_name = name
}
// double AMFProp_GetNumber(AMFObjectProperty* prop);
@ -314,12 +308,11 @@ func C_AMFProp_GetNumber(prop *C_AMFObjectProperty) float64 {
// void AMFProp_GetString(AMFObjectProperty* prop, AVal* str);
// amf.c +341
func C_AMFProp_GetString(prop *C_AMFObjectProperty, str *C_AVal) {
func C_AMFProp_GetString(prop *C_AMFObjectProperty) string {
if prop.p_type == AMF_STRING {
*str = prop.p_vu.p_aval
} else {
*str = AV_empty
return prop.p_vu.p_aval
}
return ""
}
// void AMFProp_GetObject(AMFObjectProperty *prop, AMFObject *obj);
@ -339,36 +332,30 @@ func C_AMF_PropEncode(p *C_AMFObjectProperty, pBuffer *byte, pBufEnd *byte) *byt
return nil
}
if p.p_type != AMF_NULL && int(uintptr(unsafe.Pointer(pBuffer)))+
int(p.p_name.av_len)+2+1 >= int(
uintptr(unsafe.Pointer(pBufEnd))) {
buflen := int(uintptr(unsafe.Pointer(pBufEnd)) - uintptr(unsafe.Pointer(pBuffer)))
if p.p_type != AMF_NULL && len(p.p_name)+2+1 >= buflen {
return nil
}
if p.p_type != AMF_NULL && p.p_name.av_len != 0 {
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(p.p_name.av_len >> 8)
if p.p_type != AMF_NULL && len(p.p_name) != 0 {
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(len(p.p_name) >> 8)
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(p.p_name.av_len & 0xff)
(*[_Gi]byte)(unsafe.Pointer(pBuffer))[0] = byte(len(p.p_name) & 0xff)
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), 1))
memmove(unsafe.Pointer(pBuffer), unsafe.Pointer(p.p_name.av_val),
uintptr(p.p_name.av_len))
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(p.p_name.av_len)))
copy((*[_Gi]byte)(unsafe.Pointer(pBuffer))[:], p.p_name)
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), len(p.p_name)))
}
switch p.p_type {
case AMF_NUMBER:
pBuffer = C_AMF_EncodeNumber(pBuffer, pBufEnd, float64(p.p_vu.p_number))
case AMF_BOOLEAN:
val := 0
if p.p_vu.p_number != 0 {
val = 1
}
pBuffer = C_AMF_EncodeBoolean(pBuffer, pBufEnd, val)
pBuffer = C_AMF_EncodeBoolean(pBuffer, pBufEnd, p.p_vu.p_number != 0)
case AMF_STRING:
pBuffer = C_AMF_EncodeString(pBuffer, pBufEnd, &p.p_vu.p_aval)
pBuffer = C_AMF_EncodeString(pBuffer, pBufEnd, p.p_vu.p_aval)
case AMF_NULL:
if uintptr(incBytePtr(unsafe.Pointer(pBuffer), 1)) >= uintptr(unsafe.Pointer(
pBufEnd)) {
buflen = int(uintptr(unsafe.Pointer(pBufEnd)) - uintptr(unsafe.Pointer(pBuffer)))
if 1 >= buflen {
return nil
}
*(*byte)(unsafe.Pointer(pBuffer)) = AMF_NULL
@ -434,7 +421,7 @@ func C_AMF3ReadInteger(data *byte, valp *int32) int32 {
// int AMF3ReadString(const char *data, AVal *str);
// amf.c +466
func C_AMF3ReadString(data *byte, str *C_AVal) int32 {
func C_AMF3ReadString(data *byte, str *string) int32 {
var ref int32
// assert elided - we will get a panic if it's nil.
@ -448,13 +435,11 @@ func C_AMF3ReadString(data *byte, str *C_AVal) int32 {
// RTMP_Log(RTMP_LOGDEBUG,
// "%s, string reference, index: %d, not supported, ignoring!",
// __FUNCTION__, refIndex);
str.av_val = nil
str.av_len = 0
*str = ""
return len
} else {
nSize := (ref >> 1)
str.av_val = data
str.av_len = int32(nSize)
*str = string((*[_Gi]byte)(unsafe.Pointer(data))[:nSize])
return len + nSize
}
return len
@ -467,8 +452,7 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa
var nOriginalSize int32 = nSize
var nRes int32
prop.p_name.av_len = 0
prop.p_name.av_val = nil
prop.p_name = ""
if nSize == 0 || pBuffer == nil {
// TODO use new logger here
@ -491,7 +475,7 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa
return -1
}
C_AMF_DecodeString(pBuffer, &prop.p_name)
prop.p_name = C_AMF_DecodeString(pBuffer)
nSize -= int32(2 + nNameSize)
pBuffer = (*byte)(incBytePtr(unsafe.Pointer(pBuffer), int(2+nNameSize)))
}
@ -522,7 +506,7 @@ func C_AMFProp_Decode(prop *C_AMFObjectProperty, pBuffer *byte, nSize, bDecodeNa
if int64(nSize) < int64(nStringSize)+2 {
return -1
}
C_AMF_DecodeString(pBuffer, &prop.p_vu.p_aval)
prop.p_vu.p_aval = C_AMF_DecodeString(pBuffer)
nSize -= int32(2 + nStringSize)
case AMF_OBJECT:
@ -605,8 +589,7 @@ func C_AMFProp_Reset(prop *C_AMFObjectProperty) {
prop.p_type == AMF_STRICT_ARRAY {
C_AMF_Reset(&prop.p_vu.p_object)
} else {
prop.p_vu.p_aval.av_len = 0
prop.p_vu.p_aval.av_val = nil
prop.p_vu.p_aval = ""
}
prop.p_type = AMF_INVALID
}
@ -802,18 +785,17 @@ func C_AMF_AddProp(obj *C_AMFObject, prop *C_AMFObjectProperty) {
// AMFObjectProperty* AMF_GetProp(AMFObject *obj, const AVal* name, int nIndex);
// amf.c + 1249
func C_AMF_GetProp(obj *C_AMFObject, name *C_AVal, nIndex int32) *C_AMFObjectProperty {
func C_AMF_GetProp(obj *C_AMFObject, name string, nIndex int32) *C_AMFObjectProperty {
if nIndex >= 0 {
if nIndex < int32(obj.o_num) {
return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
int(nIndex), int(unsafe.Sizeof(*obj.o_props)))))
//return &obj.o_props[nIndex]
}
} else {
var n int32
for n = 0; n < int32(obj.o_num); n++ {
if C_AVMATCH(&(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name, name) != 0 {
for n := int32(0); n < obj.o_num; n++ {
p_name := (*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
int(n), int(unsafe.Sizeof(*obj.o_props))))).p_name
if p_name == name {
return &(*(*C_AMFObjectProperty)(incPtr(unsafe.Pointer(obj.o_props),
int(n), int(unsafe.Sizeof(*obj.o_props)))))
}

View File

@ -31,10 +31,6 @@ LICENSE
*/
package rtmp
import (
"unsafe"
)
const (
AMF_NUMBER = iota
AMF_BOOLEAN
@ -61,37 +57,6 @@ const (
// amf.h +40
type C_AMFDataType int32
// typedef struct C_AVal
// amf.h +57
type C_AVal struct {
av_val *byte
av_len int32
}
// C_AVal is in amf.h
// amf.h +62
func AVC(str string) C_AVal {
var aval C_AVal
if len(str) != 0 {
aval.av_val = &([]byte(str)[0])
} else {
aval.av_val = nil
}
aval.av_len = int32(len(str))
return aval
}
// #define AVMATCH(a1,a2)
// amf.h +63
func C_AVMATCH(a1, a2 *C_AVal) int32 {
if a1.av_len == a2.av_len && memcmp(unsafe.Pointer(a1.av_val),
unsafe.Pointer(a2.av_val), int(a1.av_len)) == 0 {
return 1
} else {
return 0
}
}
// typedef struct AMF_Object
// amf.h +67
type C_AMFObject struct {
@ -103,14 +68,14 @@ type C_AMFObject struct {
// amf.h +73
type P_vu struct {
p_number float64
p_aval C_AVal
p_aval string
p_object C_AMFObject
}
// typedef struct AMFObjectProperty
// amf.h +79
type C_AMFObjectProperty struct {
p_name C_AVal
p_name string
p_type C_AMFDataType
p_vu P_vu
p_UTCoffset int16

View File

@ -6,6 +6,7 @@ DESCRIPTION
See Readme.md
AUTHOR
Dan Kortschak <dan@ausocean.org>
Saxon Nelson-Milton <saxon@ausocean.org>
LICENSE
@ -32,303 +33,71 @@ LICENSE
package rtmp
import (
"fmt"
"log"
"net/url"
"path"
"strconv"
"strings"
"unsafe"
)
// int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
// AVal *playpath, AVal *app);
// int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, AVal *playpath, AVal *app);
// parseurl.c +33
func C_RTMP_ParseURL(url *byte, protocol *int32, host *C_AVal, port *uint32,
playpath *C_AVal, app *C_AVal) int {
var p, end, col, ques, slash *byte
// TODO: use our logger here
// RTMP_Log(RTMP_LOGDEBUG, "Parsing...");
*protocol = RTMP_PROTOCOL_RTMP
*port = 0
playpath.av_len = 0
playpath.av_val = nil
app.av_len = 0
app.av_val = nil
p = strstr(url, goStrToCStr("://"))
if p == nil {
// TODO: use our logger here
log.Println("RTMP URL: No :// in url!")
return 0
}
/*
NOTE: the following code nees to be ported if we're using anything other than
rtmp!
{
int len = (int)(p-url);
if(len == 4 && strncasecmp(url, "rtmp", 4)==0)
*protocol = RTMP_PROTOCOL_RTMP;
else if(len == 5 && strncasecmp(url, "rtmpt", 5)==0)
*protocol = RTMP_PROTOCOL_RTMPT;
else if(len == 5 && strncasecmp(url, "rtmps", 5)==0)
*protocol = RTMP_PROTOCOL_RTMPS;
else if(len == 5 && strncasecmp(url, "rtmpe", 5)==0)
*protocol = RTMP_PROTOCOL_RTMPE;
else if(len == 5 && strncasecmp(url, "rtmfp", 5)==0)
*protocol = RTMP_PROTOCOL_RTMFP;
else if(len == 6 && strncasecmp(url, "rtmpte", 6)==0)
*protocol = RTMP_PROTOCOL_RTMPTE;
else if(len == 6 && strncasecmp(url, "rtmpts", 6)==0)
*protocol = RTMP_PROTOCOL_RTMPTS;
else {
RTMP_Log(RTMP_LOGWARNING, "Unknown protocol!\n");
goto parsehost;
}
}
*/
// TODO: implement new logger here
// RTMP_Log(RTMP_LOGDEBUG, "Parsed protocol: %d", *protocol);
// Get the hostname
p = (*byte)(incBytePtr(unsafe.Pointer(p), 3))
// check for sudden death
if *p == 0 {
// TODO: use new logger here
// RTMP_Log(RTMP_LOGWARNING, "No hostname in URL!");
return 0
func C_RTMP_ParseURL(addr string) (protocol int32, host string, port uint16, app, playpath string, ok bool) {
u, err := url.Parse(addr)
if err != nil {
log.Printf("failed to parse addr: %v", err)
return protocol, host, port, app, playpath, false
}
end = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(strlen(p))))
col = strchr(p, ':')
ques = strchr(p, '?')
slash = strchr(p, '/')
{
var hostlen int32
if slash != nil {
hostlen = int32(uintptr(unsafe.Pointer(slash)) - uintptr(unsafe.Pointer(p)))
} else {
hostlen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p)))
}
if col != nil && int32(uintptr(unsafe.Pointer(col))-uintptr(unsafe.Pointer(p))) < hostlen {
hostlen = int32(uintptr(unsafe.Pointer(col)) - uintptr(unsafe.Pointer(p)))
}
if hostlen < 256 {
host.av_val = (*byte)(unsafe.Pointer(p))
host.av_len = hostlen
// TODO: use new logger with this
//RTMP_Log(RTMP_LOGDEBUG, "Parsed host : %.*s", hostlen, host.av_val);
} else {
// TODO: use new logger with this
// RTMP_Log(RTMP_LOGWARNING, "Hostname exceeds 255 characters!");
}
p = (*byte)(incBytePtr(unsafe.Pointer(p), int(hostlen)))
switch u.Scheme {
case "rtmp":
protocol = RTMP_PROTOCOL_RTMP
case "rtmpt":
protocol = RTMP_PROTOCOL_RTMPT
case "rtmps":
protocol = RTMP_PROTOCOL_RTMPS
case "rtmpe":
protocol = RTMP_PROTOCOL_RTMPE
case "rtmfp":
protocol = RTMP_PROTOCOL_RTMFP
case "rtmpte":
protocol = RTMP_PROTOCOL_RTMPTE
case "rtmpts":
protocol = RTMP_PROTOCOL_RTMPTS
default:
log.Printf("unknown scheme: %q", u.Scheme)
return protocol, host, port, app, playpath, false
}
// get port number if available
if *p == ':' {
var p2 uint32
p = (*byte)(incBytePtr(unsafe.Pointer(p), 1))
tmp, _ := strconv.Atoi(cStrToGoStr(p))
p2 = uint32(tmp)
if p2 > 65535 {
// TODO: use new logger with this
// RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");
} else {
*port = p2
host = u.Host
if p := u.Port(); p != "" {
pi, err := strconv.Atoi(p)
if err != nil {
return protocol, host, port, app, playpath, false
}
port = uint16(pi)
}
if !path.IsAbs(u.Path) {
return protocol, host, port, app, playpath, true
}
elems := strings.SplitN(u.Path[1:], "/", 3)
app = elems[0]
playpath = elems[1]
if len(elems) == 3 && len(elems[2]) != 0 {
playpath = path.Join(elems[1:]...)
switch ext := path.Ext(playpath); ext {
case ".f4v", ".mp4":
playpath = "mp4:" + playpath[:len(playpath)-len(ext)]
case ".mp3":
playpath = "mp3:" + playpath[:len(playpath)-len(ext)]
case ".flv":
playpath = playpath[:len(playpath)-len(ext)]
}
if u.RawQuery != "" {
playpath += "?" + u.RawQuery
}
}
if slash == nil {
// TODO: use new logger
// RTMP_Log(RTMP_LOGWARNING, "No application or playpath in URL!");
return 1
}
p = (*byte)(incBytePtr(unsafe.Pointer(slash), 1))
{
/* parse application
*
* rtmp://host[:port]/app[/appinstance][/...]
* application = app[/appinstance]
*/
var slash2 *byte
var slash3 *byte = nil
var slash4 *byte = nil
var applen, appnamelen int32
slash2 = strchr(p, '/')
if slash2 != nil {
slash3 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash2))+
uintptr(1))), '/')
}
if slash3 != nil {
slash4 = strchr((*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(slash3))+
uintptr(1))), '/')
}
// ondemand, pass all parameters as app
applen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p)))
appnamelen = applen
switch {
case ques != nil && strstr(p, goStrToCStr("slist=")) != nil:
appnamelen = int32(uintptr(unsafe.Pointer(ques)) - uintptr(unsafe.Pointer(p)))
case strings.Compare(cStrToGoStr(p)[:9], "ondemand/") == 0:
/* app = ondemand/foobar, only pass app=ondemand */
applen = 8
appnamelen = 8
default:
switch {
case slash4 != nil:
appnamelen = int32(uintptr(unsafe.Pointer(slash4)) - uintptr(
unsafe.Pointer(p)))
case slash3 != nil:
appnamelen = int32(uintptr(unsafe.Pointer(slash3)) - uintptr(
unsafe.Pointer(p)))
case slash2 != nil:
appnamelen = int32(uintptr(unsafe.Pointer(slash2)) - uintptr(
unsafe.Pointer(p)))
}
applen = appnamelen
}
app.av_val = (*byte)(unsafe.Pointer(p))
app.av_len = applen
// TODO: use new logging here
// RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p);
p = (*byte)(incBytePtr(unsafe.Pointer(p), int(appnamelen)))
}
if *p == '/' {
p = (*byte)(incBytePtr(unsafe.Pointer(p), 1))
}
// NOTE: don't think we currently need this section - see 787 for this func
if int(uintptr(unsafe.Pointer(end))-uintptr(unsafe.Pointer(p))) != 0 {
var av C_AVal
av.av_val = (*byte)(unsafe.Pointer(p))
av.av_len = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p)))
// TODO: port THis
//C.RTMP_ParsePlaypath(&av, playpath)
C_RTMP_ParsePlaypath(&av, playpath)
}
return 1
}
// void RTMP_ParsePlaypath(AVal *in, AVal *out);
// parseurl.c +201
func C_RTMP_ParsePlaypath(in, out *C_AVal) {
var addMP4 int32 = 0
var addMP3 int32 = 0
var subExt int32 = 0
playpath := in.av_val
var temp, q *byte
var ext *byte = nil
ppstart := (*byte)(unsafe.Pointer(playpath))
var streamname, destptr, p *byte
pplen := in.av_len
out.av_val = nil
out.av_len = 0
temp = strstr((*byte)(unsafe.Pointer(ppstart)), goStrToCStr("slist="))
if *ppstart == '?' && temp != nil {
ppstart = (*byte)(incBytePtr(unsafe.Pointer(temp), 6))
pplen = strlen(ppstart)
temp = strchr(ppstart, '&')
if temp != nil {
pplen = int32(uintptr(unsafe.Pointer(temp)) - uintptr(unsafe.Pointer(ppstart)))
}
}
q = strchr(ppstart, '?')
if pplen >= 4 {
if q != nil {
ext = (*byte)(decBytePtr(unsafe.Pointer(q), 4))
} else {
ext = (*byte)(sliceToPtr((*[_Gi]byte)(unsafe.Pointer(ppstart))[uintptr(pplen)-4:]))
}
switch {
case strings.Compare(cStrToGoStr(ext)[:4], ".f4v") == 0 ||
strings.Compare(cStrToGoStr(ext)[:4], ".mp4") == 0:
addMP4 = 1
subExt = 1
case ppstart == (*byte)(unsafe.Pointer(playpath)) && strings.Compare(
cStrToGoStr(ext)[:4], ".flv") == 0:
subExt = 1
case strings.Compare(cStrToGoStr(ext)[:4], ".mp3") == 0:
addMP3 = 1
subExt = 1
}
}
streamname = (*byte)(malloc(uintptr(pplen + 4 + 1)))
if streamname == nil {
return
}
destptr = streamname
switch {
case addMP4 != 0:
if strings.Compare(cStrToGoStr(ppstart)[:4], "mp4") != 0 {
memmove(unsafe.Pointer(destptr), unsafe.Pointer(goStrToCStr("mp4:")),
uintptr(len("mp4:")))
destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 4))
} else {
subExt = 0
}
case addMP3 != 0:
if strings.Compare(cStrToGoStr(ppstart)[:4], "mp3") != 0 {
memmove(unsafe.Pointer(destptr), unsafe.Pointer(goStrToCStr("mp3:")),
uintptr(len("mp4:")))
destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 4))
} else {
subExt = 0
}
}
p = ppstart
for pplen > 0 {
if subExt != 0 && p == ext {
p = (*byte)(incBytePtr(unsafe.Pointer(p), 4))
pplen -= 4
continue
}
if *p == '%' {
var c uint32
fmt.Sscanf(cStrToGoStr((*byte)(incBytePtr(unsafe.Pointer(p), 1))), "%02x", &c)
(*[_Gi]byte)(unsafe.Pointer(destptr))[0] = byte(c)
destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 1))
pplen -= 3
p = (*byte)(incBytePtr(unsafe.Pointer(p), 3))
} else {
(*[_Gi]byte)(unsafe.Pointer(destptr))[0] = *p
destptr = (*byte)(incBytePtr(unsafe.Pointer(destptr), 1))
p = (*byte)(incBytePtr(unsafe.Pointer(p), 1))
pplen--
}
}
*destptr = '\x00'
out.av_val = (*byte)(unsafe.Pointer(streamname))
out.av_len = int32(uintptr(unsafe.Pointer(destptr)) - uintptr(unsafe.Pointer(
streamname)))
return protocol, host, port, app, playpath, true
}

File diff suppressed because it is too large Load Diff

View File

@ -142,65 +142,46 @@ type C_RTMPSockBuf struct {
sb_start *byte
sb_buf [RTMP_BUFFER_CACHE_SIZE]byte // port const
sb_timedout int32
sb_ssl uintptr
}
// RTMPPacket_IsReady(a)
// rtmp.h +142
func C_RTMPPacket_IsReady(p *C_RTMPPacket) int {
if p.m_nBytesRead == p.m_nBodySize {
return 1
}
return 0
func C_RTMPPacket_IsReady(p *C_RTMPPacket) bool {
return p.m_nBytesRead == p.m_nBodySize
}
// typedef struct RTMP_LNK
// rtmp.h +144
type C_RTMP_LNK struct {
hostname C_AVal
sockshost C_AVal
playpath0 C_AVal
playpath C_AVal
tcUrl C_AVal
swfUrl C_AVal
pageUrl C_AVal
app C_AVal
auth C_AVal
flashVer C_AVal
subscribepath C_AVal
usherToken C_AVal
token C_AVal
pubUser C_AVal
pubPasswd C_AVal
extras C_AMFObject
edepth int32
seekTime int32
stopTime int32
lFlags int32
swfAge int32
protocol int32
timeout int32
pFlags int32
socksport uint16
port uint16
hostname string
sockshost string
playpath0 string
playpath string
tcUrl string
swfUrl string
pageUrl string
app string
auth string
flashVer string
token string
extras C_AMFObject
seekTime int32
lFlags int32
swfAge int32
protocol int32
timeout int32
socksport uint16
port uint16
}
// typedef struct RTMP_READ
// rtmp.h +200
type C_RTMP_READ struct {
buf *byte
bufpos *byte
buflen uint
timestamp uint32
dataType uint8
flags uint8
status int8
initialFrameType uint8
nResumeTS uint32
metaHeader *byte
initialFrame *byte
nMetaHeaderSize uint32
nInitialFrameSize uint32
nIgnoredFrameCounter uint32
nIgnoredFlvFrameCounter uint32
}
@ -208,7 +189,7 @@ type C_RTMP_READ struct {
// typedef struct RTMPMethod
// rtmp.h +231
type C_RTMP_METHOD struct {
name C_AVal
name string
num int32
}
@ -223,13 +204,11 @@ type C_RTMP struct {
m_nBufferMS int32
m_stream_id int32
m_mediaChannel int32
m_mediaStamp uint32
m_pauseStamp uint32
m_pausing int32
m_nServerBW int32
m_nClientBW int32
m_nClientBW2 uint8
m_bPlaying uint8
m_bPlaying bool
m_bSendEncoding uint8
m_bSendCounter uint8
m_numInvokes int32
@ -245,10 +224,8 @@ type C_RTMP struct {
m_fEncoding float64
m_fDuration float64
m_msgCounter int32
m_polling int32
m_resplen int32
m_unackd int32
m_clientID C_AVal
m_read C_RTMP_READ
m_write C_RTMPPacket
m_sb C_RTMPSockBuf

View File

@ -76,7 +76,7 @@ func TestMemset(t *testing.T) {
setNum := 5
testVal := byte('A')
mem := malloc(uintptr(size))
memset((*byte)(mem), int(testVal), setNum)
memset((*byte)(mem), testVal, setNum)
for i := 0; i < size; i++ {
if i > setNum-1 {
testVal = byte(0)