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
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)))
}
// 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
}
}
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: default:
switch { log.Printf("unknown scheme: %q", u.Scheme)
case slash4 != nil: return protocol, host, port, app, playpath, false
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 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)
} }
app.av_val = (*byte)(unsafe.Pointer(p)) if !path.IsAbs(u.Path) {
app.av_len = applen return protocol, host, port, app, playpath, true
// TODO: use new logging here
// RTMP_Log(RTMP_LOGDEBUG, "Parsed app : %.*s", applen, p);
p = (*byte)(incBytePtr(unsafe.Pointer(p), int(appnamelen)))
} }
elems := strings.SplitN(u.Path[1:], "/", 3)
if *p == '/' { app = elems[0]
p = (*byte)(incBytePtr(unsafe.Pointer(p), 1)) 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)]
} }
// NOTE: don't think we currently need this section - see 787 for this func if u.RawQuery != "" {
playpath += "?" + u.RawQuery
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, '?') return protocol, host, port, app, playpath, true
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,45 +142,34 @@ 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
token C_AVal
pubUser C_AVal
pubPasswd C_AVal
extras C_AMFObject extras C_AMFObject
edepth int32
seekTime int32 seekTime int32
stopTime int32
lFlags int32 lFlags int32
swfAge int32 swfAge int32
protocol int32 protocol int32
timeout int32 timeout int32
pFlags int32
socksport uint16 socksport uint16
port uint16 port uint16
} }
@ -189,18 +178,10 @@ type C_RTMP_LNK struct {
// 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)