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

View File

@ -31,10 +31,6 @@ LICENSE
*/ */
package rtmp package rtmp
import (
"unsafe"
)
const ( const (
AMF_NUMBER = iota AMF_NUMBER = iota
AMF_BOOLEAN AMF_BOOLEAN
@ -61,37 +57,6 @@ const (
// amf.h +40 // amf.h +40
type C_AMFDataType int32 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 // typedef struct AMF_Object
// amf.h +67 // amf.h +67
type C_AMFObject struct { type C_AMFObject struct {
@ -103,14 +68,14 @@ type C_AMFObject struct {
// amf.h +73 // amf.h +73
type P_vu struct { type P_vu struct {
p_number float64 p_number float64
p_aval C_AVal p_aval string
p_object C_AMFObject p_object C_AMFObject
} }
// typedef struct AMFObjectProperty // typedef struct AMFObjectProperty
// amf.h +79 // amf.h +79
type C_AMFObjectProperty struct { type C_AMFObjectProperty struct {
p_name C_AVal p_name string
p_type C_AMFDataType p_type C_AMFDataType
p_vu P_vu p_vu P_vu
p_UTCoffset int16 p_UTCoffset int16

View File

@ -6,6 +6,7 @@ DESCRIPTION
See Readme.md See Readme.md
AUTHOR AUTHOR
Dan Kortschak <dan@ausocean.org>
Saxon Nelson-Milton <saxon@ausocean.org> Saxon Nelson-Milton <saxon@ausocean.org>
LICENSE LICENSE
@ -32,303 +33,71 @@ LICENSE
package rtmp package rtmp
import ( import (
"fmt"
"log" "log"
"net/url"
"path"
"strconv" "strconv"
"strings" "strings"
"unsafe"
) )
// int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, // int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, AVal *playpath, AVal *app);
// AVal *playpath, AVal *app);
// parseurl.c +33 // parseurl.c +33
func C_RTMP_ParseURL(url *byte, protocol *int32, host *C_AVal, port *uint32, func C_RTMP_ParseURL(addr string) (protocol int32, host string, port uint16, app, playpath string, ok bool) {
playpath *C_AVal, app *C_AVal) int { u, err := url.Parse(addr)
if err != nil {
var p, end, col, ques, slash *byte log.Printf("failed to parse addr: %v", err)
// TODO: use our logger here return protocol, host, port, app, playpath, false
// 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
} }
end = (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + uintptr(strlen(p)))) switch u.Scheme {
col = strchr(p, ':') case "rtmp":
ques = strchr(p, '?') protocol = RTMP_PROTOCOL_RTMP
slash = strchr(p, '/') case "rtmpt":
protocol = RTMP_PROTOCOL_RTMPT
{ case "rtmps":
var hostlen int32 protocol = RTMP_PROTOCOL_RTMPS
if slash != nil { case "rtmpe":
hostlen = int32(uintptr(unsafe.Pointer(slash)) - uintptr(unsafe.Pointer(p))) protocol = RTMP_PROTOCOL_RTMPE
} else { case "rtmfp":
hostlen = int32(uintptr(unsafe.Pointer(end)) - uintptr(unsafe.Pointer(p))) protocol = RTMP_PROTOCOL_RTMFP
} case "rtmpte":
if col != nil && int32(uintptr(unsafe.Pointer(col))-uintptr(unsafe.Pointer(p))) < hostlen { protocol = RTMP_PROTOCOL_RTMPTE
hostlen = int32(uintptr(unsafe.Pointer(col)) - uintptr(unsafe.Pointer(p))) case "rtmpts":
} protocol = RTMP_PROTOCOL_RTMPTS
default:
if hostlen < 256 { log.Printf("unknown scheme: %q", u.Scheme)
host.av_val = (*byte)(unsafe.Pointer(p)) return protocol, host, port, app, playpath, false
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)))
} }
// get port number if available host = u.Host
if *p == ':' { if p := u.Port(); p != "" {
var p2 uint32 pi, err := strconv.Atoi(p)
p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) if err != nil {
tmp, _ := strconv.Atoi(cStrToGoStr(p)) return protocol, host, port, app, playpath, false
p2 = uint32(tmp) }
if p2 > 65535 { port = uint16(pi)
// TODO: use new logger with this }
// RTMP_Log(RTMP_LOGWARNING, "Invalid port number!");
} else { if !path.IsAbs(u.Path) {
*port = p2 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 { return protocol, host, port, app, playpath, true
// 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)))
} }

File diff suppressed because it is too large Load Diff

View File

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

View File

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