diff --git a/docs/resources/live_transcoding.md b/docs/resources/live_transcoding.md index f0e4701b86b..564f391760e 100644 --- a/docs/resources/live_transcoding.md +++ b/docs/resources/live_transcoding.md @@ -50,15 +50,22 @@ Changing this parameter will create a new resource. * `video_encoding` - (Required, String) Specifies the video codec. The valid values are **H264** and **H265**. -* `templates` - (Required, List) Specifies the video quality templates. -The [object](#templates_resource) structure is documented below. A maximum of `4` templates can be added. -For resolution and bitrate settings in the presets, -please refer to the [document](https://support.huaweicloud.com/intl/en-us/usermanual-live/live01000802.html). +* `templates` - (Required, List) Specifies the video quality templates. A maximum of `4` templates can be added. + The [templates](#transcoding_templates) structure is documented below. + For resolution and bitrate settings in the presets, + please refer to the [document](https://support.huaweicloud.com/intl/en-us/usermanual-live/live01000802.html). + +* `trans_type` - (Optional, String) Specifies the transcoding stream trigger mode. + The valid values are as follows: + + **play**: Pull stream triggers transcoding. + + **publish**: Push stream triggers transcoding. + + Defaults to **play**. * `low_bitrate_hd` - (Optional, Bool) Specifies whether to enable low bitrate HD rates. If enabled the output media will have a lower bitrate with the same image quality. Defaults to **false**. - + The `templates` block supports: * `name` - (Required, String) Specifies the template name. The name can contain a maximum of 64 characters, and only @@ -77,6 +84,40 @@ contains letters, digits and hyphens (-). * `frame_rate` - (Optional, Int) Specifies the frame rate of the transcoded video, in fps. Value range: `0` ~ `30`. Value 0 indicates that the frame rate remains unchanged. +* `protocol` - (Optional, String) Specifies the protocol type supported for transcoding output. + The valid value is **RTMP**. Defaults to **RTMP**. + +* `i_frame_interval` - (Optional, String) Specifies the maximum I-frame interval in frames. + The value ranges from `0` to `500`, includes `0` and `500`. Defaults to `50`. + + -> If you want to set the i-frame interval through `i_frame_interval`, please set the `gop` to `0` or do not pass the + `gop` parameter. + +* `gop` - (Optional, String) Specifies the interval time for I-frames, in seconds. + The value ranges from `0` to `10`, includes `0` and `10`. Defaults to `2`. + + -> When `gop` is not `0`, the i-frame interval is set with the `gop` parameter, and the `i_frame_interval` field does + not take effect. + +* `bitrate_adaptive` - (Optional, String) Specifies the adaptive bitrate. + The valid values are as follows: + + **off**: Disable rate adaptation and output the target rate according to the set rate. + + **minimum**: Output the target bitrate based on the minimum value of the set bitrate and source file bitrate. + + **adaptive**: Adaptive output of target bitrate based on source file bitrate. + + Defaults to **off**. + +* `i_frame_policy` - (Optional, String) Specifies the encoding output I-frame strategy. + The valid values are as follows: + + **auto**: I-frame output according to the set `gop` duration. + + **strictSync**: The encoded output I-frame is completely consistent with the source, and the `gop` parameter is + invalid after setting this value. + + Defaults to **auto**. + + -> In multi bitrate scenarios, it is recommended to enable I-frame random source to ensure alignment of multi bitrate + I-frames. + ## Attribute Reference In addition to all arguments above, the following attributes are exported: diff --git a/huaweicloud/services/acceptance/live/resource_huaweicloud_live_transcoding_test.go b/huaweicloud/services/acceptance/live/resource_huaweicloud_live_transcoding_test.go index d17a9949b9d..e3e748b6178 100644 --- a/huaweicloud/services/acceptance/live/resource_huaweicloud_live_transcoding_test.go +++ b/huaweicloud/services/acceptance/live/resource_huaweicloud_live_transcoding_test.go @@ -50,12 +50,18 @@ func TestAccTranscoding_basic(t *testing.T) { resource.TestCheckResourceAttr(rName, "domain_name", pushDomainName), resource.TestCheckResourceAttr(rName, "app_name", "live"), resource.TestCheckResourceAttr(rName, "video_encoding", "H264"), + resource.TestCheckResourceAttr(rName, "trans_type", "play"), resource.TestCheckResourceAttr(rName, "low_bitrate_hd", "false"), resource.TestCheckResourceAttr(rName, "templates.#", "1"), resource.TestCheckResourceAttr(rName, "templates.0.name", "t1"), resource.TestCheckResourceAttr(rName, "templates.0.width", "300"), resource.TestCheckResourceAttr(rName, "templates.0.height", "400"), resource.TestCheckResourceAttr(rName, "templates.0.bitrate", "300"), + resource.TestCheckResourceAttr(rName, "templates.0.protocol", "RTMP"), + resource.TestCheckResourceAttr(rName, "templates.0.i_frame_interval", "500"), + resource.TestCheckResourceAttr(rName, "templates.0.gop", "0"), + resource.TestCheckResourceAttr(rName, "templates.0.bitrate_adaptive", "adaptive"), + resource.TestCheckResourceAttr(rName, "templates.0.i_frame_policy", "strictSync"), ), }, { @@ -64,12 +70,17 @@ func TestAccTranscoding_basic(t *testing.T) { resource.TestCheckResourceAttr(rName, "domain_name", pushDomainName), resource.TestCheckResourceAttr(rName, "app_name", "live"), resource.TestCheckResourceAttr(rName, "video_encoding", "H264"), + resource.TestCheckResourceAttr(rName, "trans_type", "play"), resource.TestCheckResourceAttr(rName, "low_bitrate_hd", "true"), resource.TestCheckResourceAttr(rName, "templates.#", "2"), resource.TestCheckResourceAttr(rName, "templates.1.name", "t2"), resource.TestCheckResourceAttr(rName, "templates.1.width", "600"), resource.TestCheckResourceAttr(rName, "templates.1.height", "800"), resource.TestCheckResourceAttr(rName, "templates.1.bitrate", "300"), + resource.TestCheckResourceAttr(rName, "templates.1.protocol", "RTMP"), + resource.TestCheckResourceAttr(rName, "templates.1.gop", "10"), + resource.TestCheckResourceAttr(rName, "templates.1.bitrate_adaptive", "minimum"), + resource.TestCheckResourceAttr(rName, "templates.1.i_frame_policy", "auto"), ), }, { @@ -77,6 +88,9 @@ func TestAccTranscoding_basic(t *testing.T) { ImportState: true, ImportStateVerify: true, ImportStateId: fmt.Sprintf("%s/live", pushDomainName), + ImportStateVerifyIgnore: []string{ + "trans_type", + }, }, }, }) @@ -93,12 +107,18 @@ resource "huaweicloud_live_transcoding" "test" { domain_name = huaweicloud_live_domain.ingestDomain.name app_name = "live" video_encoding = "H264" + trans_type = "play" templates { - name = "t1" - width = 300 - height = 400 - bitrate = 300 + name = "t1" + width = 300 + height = 400 + bitrate = 300 + protocol = "RTMP" + i_frame_interval = 500 + gop = 0 + bitrate_adaptive = "adaptive" + i_frame_policy = "strictSync" } } `, pushDomainName) @@ -115,20 +135,30 @@ resource "huaweicloud_live_transcoding" "test" { domain_name = huaweicloud_live_domain.ingestDomain.name app_name = "live" video_encoding = "H264" + trans_type = "play" low_bitrate_hd = true templates { - name = "t1" - width = 300 - height = 400 - bitrate = 300 + name = "t1" + width = 300 + height = 400 + bitrate = 300 + protocol = "RTMP" + i_frame_interval = 500 + gop = 0 + bitrate_adaptive = "adaptive" + i_frame_policy = "strictSync" } templates { - name = "t2" - width = 600 - height = 800 - bitrate = 300 + name = "t2" + width = 600 + height = 800 + bitrate = 300 + protocol = "RTMP" + gop = 10 + bitrate_adaptive = "minimum" + i_frame_policy = "auto" } } `, pushDomainName) diff --git a/huaweicloud/services/live/resource_huaweicloud_live_transcoding.go b/huaweicloud/services/live/resource_huaweicloud_live_transcoding.go index 920d7670dde..88bced93d5b 100644 --- a/huaweicloud/services/live/resource_huaweicloud_live_transcoding.go +++ b/huaweicloud/services/live/resource_huaweicloud_live_transcoding.go @@ -83,16 +83,44 @@ func ResourceTranscoding() *schema.Resource { Type: schema.TypeInt, Required: true, }, - "frame_rate": { Type: schema.TypeInt, Optional: true, Computed: true, }, + "protocol": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "i_frame_interval": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "gop": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "bitrate_adaptive": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "i_frame_policy": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, }, }, }, - + // This field is not returned by API, so the Computed attribute is not added. + "trans_type": { + Type: schema.TypeString, + Optional: true, + }, "low_bitrate_hd": { Type: schema.TypeBool, Optional: true, @@ -262,6 +290,40 @@ func buildTranscodingParams(d *schema.ResourceData) (*model.StreamTranscodingTem VideoFrameRate: utils.Int32(int32(template["frame_rate"].(int))), Codec: &codec, Hdlb: &hdlb, + IFrameInterval: convertStringValueToInt32(template["i_frame_interval"].(string)), + Gop: convertStringValueToInt32(template["gop"].(string)), + } + + if protocol := template["protocol"].(string); protocol != "" { + rtmpValue := model.GetQualityInfoProtocolEnum().RTMP + switch protocol { + case "RTMP": + qualityInfo[i].Protocol = &rtmpValue + } + } + if bitrateAdaptive := template["bitrate_adaptive"].(string); bitrateAdaptive != "" { + minimumValue := model.GetQualityInfoBitrateAdaptiveEnum().MINIMUM + adaptiveValue := model.GetQualityInfoBitrateAdaptiveEnum().ADAPTIVE + switch bitrateAdaptive { + case "off": + // There is no enumeration value for **off** in the HuaweiCloud SDK, but the default value for the API + // is **off**, so this processing is done here. + qualityInfo[i].BitrateAdaptive = nil + case "minimum": + qualityInfo[i].BitrateAdaptive = &minimumValue + case "adaptive": + qualityInfo[i].BitrateAdaptive = &adaptiveValue + } + } + if iFramePolicy := template["i_frame_policy"].(string); iFramePolicy != "" { + autoValue := model.GetQualityInfoIFramePolicyEnum().AUTO + strictSyncValue := model.GetQualityInfoIFramePolicyEnum().STRICT_SYNC + switch iFramePolicy { + case "auto": + qualityInfo[i].IFramePolicy = &autoValue + case "strictSync": + qualityInfo[i].IFramePolicy = &strictSyncValue + } } } @@ -270,6 +332,17 @@ func buildTranscodingParams(d *schema.ResourceData) (*model.StreamTranscodingTem AppName: d.Get("app_name").(string), QualityInfo: qualityInfo, } + if transType := d.Get("trans_type").(string); transType != "" { + playValue := model.GetStreamTranscodingTemplateTransTypeEnum().PLAY + publishValue := model.GetStreamTranscodingTemplateTransTypeEnum().PUBLISH + switch transType { + case "play": + req.TransType = &playValue + case "publish": + req.TransType = &publishValue + } + } + return &req, nil } @@ -279,11 +352,16 @@ func setTemplatesToState(d *schema.ResourceData, qualityInfo *[]model.QualityInf rst := make([]map[string]interface{}, len(qualitys)) for i, v := range qualitys { rst[i] = map[string]interface{}{ - "name": v.TemplateName, - "width": v.Width, - "height": v.Height, - "bitrate": v.Bitrate, - "frame_rate": v.VideoFrameRate, + "name": v.TemplateName, + "width": v.Width, + "height": v.Height, + "bitrate": v.Bitrate, + "frame_rate": v.VideoFrameRate, + "protocol": v.Protocol.Value(), + "i_frame_interval": parseInt32ValueToString(v.IFrameInterval), + "gop": parseInt32ValueToString(v.Gop), + "bitrate_adaptive": v.BitrateAdaptive.Value(), + "i_frame_policy": v.IFramePolicy.Value(), } } @@ -311,3 +389,25 @@ func parseTranscodingId(id string) (domainName string, appName string, err error } return idArrays[0], idArrays[1], nil } + +func convertStringValueToInt32(value string) *int32 { + if value == "0" { + return utils.Int32(0) + } + + parsedValue := utils.StringToInt(&value) + if parsedValue != nil { + //nolint:gosec + return utils.Int32IgnoreEmpty(int32(*parsedValue)) + } + + return nil +} + +func parseInt32ValueToString(value *int32) string { + if value != nil { + return fmt.Sprintf("%v", *value) + } + + return "" +}