This commit is contained in:
程广 2024-11-06 19:58:33 +08:00
parent cf62287db8
commit 21548f76b6
6 changed files with 381 additions and 28 deletions

View File

@ -215,6 +215,49 @@ func (d *Device) GetSnapshotUri(profileToken string) (string, error) {
return "", nil
}
func (d *Device) GetVideoSources() ([]onvifmodel.VideoSource, error) {
err := d.check()
if err != nil {
return nil, err
}
resp, err := media_sdk.Call_GetVideoSources(d.ctx, d.device, media.GetVideoSources{})
if err != nil {
return nil, err
}
return resp.VideoSources, nil
}
func (d *Device) GetVideoSourceConfigurations() ([]onvifmodel.VideoSourceConfiguration, error) {
err := d.check()
if err != nil {
return nil, err
}
resp, err := media_sdk.Call_GetVideoSourceConfigurations(d.ctx, d.device, media.GetVideoSourceConfigurations{})
if err != nil {
return nil, err
}
return resp.Configurations, nil
}
func (d *Device) RelateVideoSource(profileToken, videoSourceToken string) error {
err := d.check()
if err != nil {
return err
}
profileResp, err := media_sdk.Call_GetProfile(d.ctx, d.device, media.GetProfile{ProfileToken: onvifmodel.ReferenceToken(profileToken)})
if err != nil {
return err
}
profile := profileResp.Profile
profile.VideoSourceConfiguration.SourceToken = onvifmodel.ReferenceToken(videoSourceToken)
// profile.VideoSourceConfiguration.Name = onvifmodel.Name(videoSourceToken)
_, serr := media_sdk.Call_SetVideoSourceConfiguration(d.ctx, d.device, media.SetVideoSourceConfiguration{Configuration: profile.VideoSourceConfiguration, ForcePersistence: xsd.Boolean(true)})
if serr != nil {
return serr
}
_, aerr := media_sdk.Call_AddVideoSourceConfiguration(d.ctx, d.device, media.AddVideoSourceConfiguration{ProfileToken: onvifmodel.ReferenceToken(profileToken), ConfigurationToken: profile.VideoSourceConfiguration.Token})
return aerr
}
func (d *Device) GetProfiles() ([]onvifmodel.Profile, error) {
err := d.check()
if err != nil {
@ -226,6 +269,17 @@ func (d *Device) GetProfiles() ([]onvifmodel.Profile, error) {
}
return resp.Profiles, nil
}
func (d *Device) GetVideoEncoderConfigurations() ([]onvifmodel.VideoEncoderConfiguration, error) {
err := d.check()
if err != nil {
return nil, err
}
resp, err := media_sdk.Call_GetVideoEncoderConfigurations(d.ctx, d.device, media.GetVideoEncoderConfigurations{})
if err != nil {
return nil, err
}
return resp.Configurations, nil
}
func (d *Device) GetDeviceInformation() (interface{}, error) {
err := d.check()

View File

@ -5,9 +5,17 @@ import (
"testing"
"time"
"os"
"git.pyer.club/kingecg/goonvif/onvif"
)
func TestMain(m *testing.M) {
os.Setenv("DEBUG", "DEBUG")
result := m.Run()
os.Unsetenv("DEBUG")
os.Exit(result)
}
func TestListInterfaces(t *testing.T) {
ifaces, err := listLocalNetworkInterfaces()
if err != nil {
@ -114,7 +122,7 @@ func TestGetStreamUri(t *testing.T) {
},
}
uri, err := d.GetStreamUriUdp("")
uri, err := d.GetStreamUriUdp("Profile_1")
if err != nil {
t.Errorf("Expected no error, got %v", err)
return
@ -146,3 +154,77 @@ func TestZoom(t *testing.T) {
t.Fatal(err)
}
}
func TestGetProfiles(t *testing.T) {
d := NewDevice(onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
})
response, err := d.GetCapabilities()
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
t.Log(response)
profiles, err := d.GetProfiles()
if err != nil {
t.Fatal(err)
}
t.Log(profiles)
}
func TestGetVideoSource(t *testing.T) {
d := NewDevice(onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
})
videoSource, err := d.GetVideoSources()
if err != nil {
t.Fatal(err)
}
t.Log(videoSource) //"VideoSource_1"
}
func TestGetVideoSourceConfigurations(t *testing.T) {
d := NewDevice(onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
})
videoSource, err := d.GetVideoSourceConfigurations()
if err != nil {
t.Fatal(err)
}
t.Log(videoSource)
}
func TestRelateVideoSource(t *testing.T) {
d := NewDevice(onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
})
if err := d.RelateVideoSource("Profile_1", "VideoSource_1"); err != nil {
t.Fatal(err)
}
p, err := d.GetProfiles()
if err != nil {
t.Fatal(err)
}
t.Log(p)
}
func TestGetVideoEncoders(t *testing.T) {
d := NewDevice(onvif.DeviceParams{
Xaddr: "192.168.12.52",
Username: "dctdev",
Password: "dacenT2017",
})
encoders, err := d.GetVideoEncoderConfigurations()
if err != nil {
t.Fatal(err)
}
t.Log(encoders)
}

View File

@ -43,7 +43,7 @@ type GetVideoSources struct {
}
type GetVideoSourcesResponse struct {
VideoSources onvif.VideoSource
VideoSources []onvif.VideoSource
}
type GetAudioSources struct {
@ -255,7 +255,7 @@ type GetVideoSourceConfigurations struct {
}
type GetVideoSourceConfigurationsResponse struct {
Configurations onvif.VideoSourceConfiguration
Configurations []onvif.VideoSourceConfiguration
}
type GetVideoEncoderConfigurations struct {
@ -263,7 +263,7 @@ type GetVideoEncoderConfigurations struct {
}
type GetVideoEncoderConfigurationsResponse struct {
Configurations onvif.VideoEncoderConfiguration
Configurations []onvif.VideoEncoderConfiguration
}
type GetAudioSourceConfigurations struct {

View File

@ -37,13 +37,16 @@ func ReadAndParse(ctx context.Context, httpReply *http.Response, reply interface
return errors.Annotate(err, "read")
} else {
if httpReply.StatusCode != http.StatusOK {
if httpReply.StatusCode != http.StatusOK || os.Getenv("DEBUG") == "DEBUG" {
doc := etree.NewDocument()
doc.ReadFromBytes(b)
doc.Indent(2)
xmlstr, _ := doc.WriteToString()
Logger.Error().Str("msg", xmlstr).Msg("XMLDOC")
return errors.New("unexpected status code")
if httpReply.StatusCode != http.StatusOK {
Logger.Error().Str("msg", xmlstr).Msg("XMLDOC")
return errors.New("unexpected status code")
}
}
err = xml.Unmarshal(b, reply)
return errors.Annotate(err, "decode")

View File

@ -346,7 +346,7 @@ type Profile struct {
Fixed bool `xml:"fixed,attr"`
Name Name
VideoSourceConfiguration VideoSourceConfiguration
AudioSourceConfiguration AudioSourceConfiguration
AudioSourceConfiguration *AudioSourceConfiguration
VideoEncoderConfiguration VideoEncoderConfiguration
AudioEncoderConfiguration AudioEncoderConfiguration
VideoAnalyticsConfiguration VideoAnalyticsConfiguration
@ -357,16 +357,16 @@ type Profile struct {
type VideoSourceConfiguration struct {
ConfigurationEntity
ViewMode string `xml:"ViewMode,attr"`
SourceToken ReferenceToken `xml:"onvif:SourceToken"`
Bounds IntRectangle `xml:"onvif:Bounds"`
Extension VideoSourceConfigurationExtension `xml:"onvif:Extension"`
ViewMode string `xml:"ViewMode,attr"`
SourceToken ReferenceToken `xml:"onvif:SourceToken"`
Bounds IntRectangle `xml:"onvif:Bounds"`
Extension *VideoSourceConfigurationExtension `xml:"onvif:Extension"`
}
type ConfigurationEntity struct {
Token ReferenceToken `xml:"token,attr"`
Name Name `xml:"onvif:Name"`
UseCount int `xml:"onvif:UseCount"`
Name xsd.String `xml:"onvif:Name"`
UseCount xsd.Int `xml:"onvif:UseCount"`
}
type VideoSourceConfigurationExtension struct {

View File

@ -35,19 +35,233 @@
xmlns:tr2="http://www.onvif.org/ver20/media/wsdl"
xmlns:axt="http://www.onvif.org/ver20/analytics">
<env:Body>
<env:Fault>
<env:Code>
<env:Value>env:Receiver</env:Value>
<env:Subcode>
<env:Value>ter:ActionNotSupported</env:Value>
<env:Subcode>
<env:Value>ter:InvalidOperation</env:Value>
</env:Subcode>
</env:Subcode>
</env:Code>
<env:Reason>
<env:Text xml:lang="en">Optional Action Not Implemented</env:Text>
</env:Reason>
</env:Fault>
<trt:GetProfilesResponse>
<trt:Profiles token="Profile_1" fixed="true">
<tt:Name>mainStream</tt:Name>
<tt:VideoSourceConfiguration token="VideoSourceToken">
<tt:Name>VideoSource_1</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:SourceToken>VideoSource_1</tt:SourceToken>
<tt:Bounds x="0" y="0" width="1920" height="1080" />
</tt:VideoSourceConfiguration>
<tt:AudioSourceConfiguration token="AudioSourceConfigToken">
<tt:Name>AudioSourceConfig</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:SourceToken>AudioSourceChannel</tt:SourceToken>
</tt:AudioSourceConfiguration>
<tt:VideoEncoderConfiguration token="VideoEncoderToken_1">
<tt:Name>VideoEncoder_1</tt:Name>
<tt:UseCount>1</tt:UseCount>
<tt:Encoding>H264</tt:Encoding>
<tt:Resolution>
<tt:Width>1920</tt:Width>
<tt:Height>1080</tt:Height>
</tt:Resolution>
<tt:Quality>5.000000</tt:Quality>
<tt:RateControl>
<tt:FrameRateLimit>15</tt:FrameRateLimit>
<tt:EncodingInterval>1</tt:EncodingInterval>
<tt:BitrateLimit>256</tt:BitrateLimit>
</tt:RateControl>
<tt:H264>
<tt:GovLength>25</tt:GovLength>
<tt:H264Profile>Main</tt:H264Profile>
</tt:H264>
<tt:Multicast>
<tt:Address>
<tt:Type>IPv4</tt:Type>
<tt:IPv4Address>0.0.0.0</tt:IPv4Address>
</tt:Address>
<tt:Port>8600</tt:Port>
<tt:TTL>128</tt:TTL>
<tt:AutoStart>false</tt:AutoStart>
</tt:Multicast>
<tt:SessionTimeout>PT5S</tt:SessionTimeout>
</tt:VideoEncoderConfiguration>
<tt:AudioEncoderConfiguration token="MainAudioEncoderToken">
<tt:Name>AudioEncoderConfig</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:Encoding>G711</tt:Encoding>
<tt:Bitrate>64</tt:Bitrate>
<tt:SampleRate>8</tt:SampleRate>
<tt:Multicast>
<tt:Address>
<tt:Type>IPv4</tt:Type>
<tt:IPv4Address>0.0.0.0</tt:IPv4Address>
</tt:Address>
<tt:Port>8602</tt:Port>
<tt:TTL>128</tt:TTL>
<tt:AutoStart>false</tt:AutoStart>
</tt:Multicast>
<tt:SessionTimeout>PT5S</tt:SessionTimeout>
</tt:AudioEncoderConfiguration>
<tt:VideoAnalyticsConfiguration token="VideoAnalyticsToken">
<tt:Name>VideoAnalyticsName</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:AnalyticsEngineConfiguration>
<tt:AnalyticsModule Name="MyCellMotionModule" Type="tt:CellMotionEngine">
<tt:Parameters>
<tt:SimpleItem Name="Sensitivity" Value="100" />
<tt:ElementItem Name="Layout">
<tt:CellLayout Columns="22" Rows="18">
<tt:Transformation>
<tt:Translate x="-1.000000" y="-1.000000" />
<tt:Scale x="0.090909" y="0.111111" />
</tt:Transformation>
</tt:CellLayout>
</tt:ElementItem>
</tt:Parameters>
</tt:AnalyticsModule>
</tt:AnalyticsEngineConfiguration>
<tt:RuleEngineConfiguration>
<tt:Rule Name="MyMotionDetectorRule" Type="tt:CellMotionDetector">
<tt:Parameters>
<tt:SimpleItem Name="MinCount" Value="5" />
<tt:SimpleItem Name="AlarmOnDelay" Value="1000" />
<tt:SimpleItem Name="AlarmOffDelay" Value="1000" />
<tt:SimpleItem Name="ActiveCells"
Value="7gAeB///H//8f//x///H//8f//x///H//8f//x///H//wA==" />
</tt:Parameters>
</tt:Rule>
</tt:RuleEngineConfiguration>
</tt:VideoAnalyticsConfiguration>
<tt:PTZConfiguration token="PTZToken">
<tt:Name>PTZ</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:NodeToken>PTZNODETOKEN</tt:NodeToken>
<tt:DefaultContinuousPanTiltVelocitySpace>
http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace</tt:DefaultContinuousPanTiltVelocitySpace>
<tt:DefaultContinuousZoomVelocitySpace>
http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace</tt:DefaultContinuousZoomVelocitySpace>
<tt:DefaultPTZTimeout>PT300S</tt:DefaultPTZTimeout>
</tt:PTZConfiguration>
<tt:Extension>
<tt:AudioOutputConfiguration token="AudioOutputConfigToken">
<tt:Name>AudioOutputConfigName</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:OutputToken>AudioOutputToken</tt:OutputToken>
<tt:SendPrimacy>www.onvif.org/ver20/HalfDuplex/Auto</tt:SendPrimacy>
<tt:OutputLevel>10</tt:OutputLevel>
</tt:AudioOutputConfiguration>
<tt:AudioDecoderConfiguration token="AudioDecoderConfigToken">
<tt:Name>AudioDecoderConfig</tt:Name>
<tt:UseCount>2</tt:UseCount>
</tt:AudioDecoderConfiguration>
</tt:Extension>
</trt:Profiles>
<trt:Profiles token="Profile_2" fixed="true">
<tt:Name>subStream</tt:Name>
<tt:VideoSourceConfiguration token="VideoSourceToken">
<tt:Name>VideoSource_1</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:SourceToken>VideoSource_1</tt:SourceToken>
<tt:Bounds x="0" y="0" width="1920" height="1080" />
</tt:VideoSourceConfiguration>
<tt:AudioSourceConfiguration token="AudioSourceConfigToken">
<tt:Name>AudioSourceConfig</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:SourceToken>AudioSourceChannel</tt:SourceToken>
</tt:AudioSourceConfiguration>
<tt:VideoEncoderConfiguration token="VideoEncoderToken_2" encoding="H265">
<tt:Name>VideoEncoder_2</tt:Name>
<tt:UseCount>1</tt:UseCount>
<tt:Encoding>H264</tt:Encoding>
<tt:Resolution>
<tt:Width>640</tt:Width>
<tt:Height>360</tt:Height>
</tt:Resolution>
<tt:Quality>3.000000</tt:Quality>
<tt:RateControl>
<tt:FrameRateLimit>18</tt:FrameRateLimit>
<tt:EncodingInterval>1</tt:EncodingInterval>
<tt:BitrateLimit>128</tt:BitrateLimit>
</tt:RateControl>
<tt:H264>
<tt:GovLength>50</tt:GovLength>
<tt:H264Profile>Main</tt:H264Profile>
</tt:H264>
<tt:Multicast>
<tt:Address>
<tt:Type>IPv4</tt:Type>
<tt:IPv4Address>0.0.0.0</tt:IPv4Address>
</tt:Address>
<tt:Port>8606</tt:Port>
<tt:TTL>128</tt:TTL>
<tt:AutoStart>false</tt:AutoStart>
</tt:Multicast>
<tt:SessionTimeout>PT5S</tt:SessionTimeout>
</tt:VideoEncoderConfiguration>
<tt:AudioEncoderConfiguration token="MainAudioEncoderToken">
<tt:Name>AudioEncoderConfig</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:Encoding>G711</tt:Encoding>
<tt:Bitrate>64</tt:Bitrate>
<tt:SampleRate>8</tt:SampleRate>
<tt:Multicast>
<tt:Address>
<tt:Type>IPv4</tt:Type>
<tt:IPv4Address>0.0.0.0</tt:IPv4Address>
</tt:Address>
<tt:Port>8602</tt:Port>
<tt:TTL>128</tt:TTL>
<tt:AutoStart>false</tt:AutoStart>
</tt:Multicast>
<tt:SessionTimeout>PT5S</tt:SessionTimeout>
</tt:AudioEncoderConfiguration>
<tt:VideoAnalyticsConfiguration token="VideoAnalyticsToken">
<tt:Name>VideoAnalyticsName</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:AnalyticsEngineConfiguration>
<tt:AnalyticsModule Name="MyCellMotionModule" Type="tt:CellMotionEngine">
<tt:Parameters>
<tt:SimpleItem Name="Sensitivity" Value="100" />
<tt:ElementItem Name="Layout">
<tt:CellLayout Columns="22" Rows="18">
<tt:Transformation>
<tt:Translate x="-1.000000" y="-1.000000" />
<tt:Scale x="0.090909" y="0.111111" />
</tt:Transformation>
</tt:CellLayout>
</tt:ElementItem>
</tt:Parameters>
</tt:AnalyticsModule>
</tt:AnalyticsEngineConfiguration>
<tt:RuleEngineConfiguration>
<tt:Rule Name="MyMotionDetectorRule" Type="tt:CellMotionDetector">
<tt:Parameters>
<tt:SimpleItem Name="MinCount" Value="5" />
<tt:SimpleItem Name="AlarmOnDelay" Value="1000" />
<tt:SimpleItem Name="AlarmOffDelay" Value="1000" />
<tt:SimpleItem Name="ActiveCells"
Value="7gAeB///H//8f//x///H//8f//x///H//8f//x///H//wA==" />
</tt:Parameters>
</tt:Rule>
</tt:RuleEngineConfiguration>
</tt:VideoAnalyticsConfiguration>
<tt:PTZConfiguration token="PTZToken">
<tt:Name>PTZ</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:NodeToken>PTZNODETOKEN</tt:NodeToken>
<tt:DefaultContinuousPanTiltVelocitySpace>
http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace</tt:DefaultContinuousPanTiltVelocitySpace>
<tt:DefaultContinuousZoomVelocitySpace>
http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace</tt:DefaultContinuousZoomVelocitySpace>
<tt:DefaultPTZTimeout>PT300S</tt:DefaultPTZTimeout>
</tt:PTZConfiguration>
<tt:Extension>
<tt:AudioOutputConfiguration token="AudioOutputConfigToken">
<tt:Name>AudioOutputConfigName</tt:Name>
<tt:UseCount>2</tt:UseCount>
<tt:OutputToken>AudioOutputToken</tt:OutputToken>
<tt:SendPrimacy>www.onvif.org/ver20/HalfDuplex/Auto</tt:SendPrimacy>
<tt:OutputLevel>10</tt:OutputLevel>
</tt:AudioOutputConfiguration>
<tt:AudioDecoderConfiguration token="AudioDecoderConfigToken">
<tt:Name>AudioDecoderConfig</tt:Name>
<tt:UseCount>2</tt:UseCount>
</tt:AudioDecoderConfiguration>
</tt:Extension>
</trt:Profiles>
</trt:GetProfilesResponse>
</env:Body>
</env:Envelope>