diff --git a/.changelog/2569.txt b/.changelog/2569.txt new file mode 100644 index 0000000000..b23a2947c4 --- /dev/null +++ b/.changelog/2569.txt @@ -0,0 +1,19 @@ +```release-note:enhancement +resource/tencentcloud_vod_adaptive_dynamic_streaming_template: Add vcrf, gop, preserve_hdr_switch, codec_tag. Adjust resource unique id to subAppId#templateId. +``` + +```release-note:enhancement +resource/tencentcloud_vod_image_sprite_template: Add format, type. Adjust resource unique id to subAppId#templateId. +``` + +```release-note:enhancement +resource/tencentcloud_vod_procedure_template: Update params media_process_task, add ai_analysis_task, ai_recognition_task, review_audio_video_task, type. Adjust resource unique id to subAppId#templateId. +``` + +```release-note:enhancement +resource/tencentcloud_vod_sample_snapshot_template: Adjust resource unique id to subAppId#templateId. +``` + +```release-note:enhancement +resource/tencentcloud_vod_snapshot_by_time_offset_template: Add type. Adjust resource unique id to subAppId#templateId. +``` diff --git a/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.go b/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.go index af14e6810f..4bb304400a 100644 --- a/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.go +++ b/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.go @@ -5,12 +5,14 @@ import ( "fmt" "log" "strconv" + "strings" "time" tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" vod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod/v20180717" "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" @@ -66,7 +68,7 @@ func ResourceTencentCloudVodAdaptiveDynamicStreamingTemplate() *schema.Resource "sub_app_id": { Type: schema.TypeInt, Optional: true, - Description: "Subapplication ID in VOD. If you need to access a resource in a subapplication, enter the subapplication ID in this field; otherwise, leave it empty.", + Description: "The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID.", }, "stream_info": { Type: schema.TypeList, @@ -123,6 +125,40 @@ func ResourceTencentCloudVodAdaptiveDynamicStreamingTemplate() *schema.Resource ValidateFunc: tccommon.ValidateAllowedStringValue([]string{"stretch", "black"}), Description: "Fill type. Fill refers to the way of processing a screenshot when its aspect ratio is different from that of the source video. The following fill types are supported: `stretch`: stretch. The screenshot will be stretched frame by frame to match the aspect ratio of the source video, which may make the screenshot shorter or longer; `black`: fill with black. This option retains the aspect ratio of the source video for the screenshot and fills the unmatched area with black color blocks. Default value: black. Note: this field may return null, indicating that no valid values can be obtained.", }, + "vcrf": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Video constant bit rate control factor, value range is [1,51].\n" + + "Note:\n" + + "- If this parameter is specified, the bitrate control method of CRF will be used for transcoding (the video bitrate will no longer take effect);\n" + + "- This field is required when the video stream encoding format is H.266. The recommended value is 28;\n" + + "- If there are no special requirements, it is not recommended to specify this parameter.", + }, + "gop": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Interval between Keyframe I frames, value range: 0 and [1, 100000], unit: number of frames. When you fill in 0 or leave it empty, the gop length is automatically set.", + }, + "preserve_hdr_switch": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Whether the transcoding output still maintains HDR when the original video is HDR (High Dynamic Range). Value range:\n" + + "- ON: if the original file is HDR, the transcoding output remains HDR;, otherwise the transcoding output is SDR (Standard Dynamic Range);\n" + + "- OFF: regardless of whether the original file is HDR or SDR, the transcoding output is SDR;\n" + + "Default value: OFF.", + }, + "codec_tag": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Encoding label, valid only if the encoding format of the video stream is H.265 encoding. Available values:\n" + + "- hvc1: stands for hvc1 tag;\n" + + "- hev1: stands for the hev1 tag;\n" + + "Default value: hvc1.", + }, }, }, }, @@ -164,6 +200,37 @@ func ResourceTencentCloudVodAdaptiveDynamicStreamingTemplate() *schema.Resource Default: false, Description: "Whether to remove audio stream. Valid values: `false`: no, `true`: yes. `false` by default.", }, + "remove_video": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "Whether to remove video stream. Valid values: `false`: no, `true`: yes. `false` by default.", + }, + "tehd_config": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + MinItems: 1, + Description: "Extremely fast HD transcoding parameters.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + Description: "Extreme high-speed HD type, available values:\n" + + "- TEHD-100: super high definition-100th;\n" + + "- OFF: turn off Ultra High definition.", + }, + "max_video_bitrate": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Video bitrate limit, which is valid when Type specifies extreme speed HD type. If you leave it empty or enter 0, there is no video bitrate limit.", + }, + }, + }, + }, }, }, }, @@ -200,8 +267,12 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateCreate(d *schema.Res if v, ok := d.GetOk("comment"); ok { request.Comment = helper.String(v.(string)) } + var resourceId string if v, ok := d.GetOk("sub_app_id"); ok { - request.SubAppId = helper.IntUint64(v.(int)) + subAppId := v.(int) + resourceId += helper.IntToStr(subAppId) + resourceId += tccommon.FILED_SP + request.SubAppId = helper.IntUint64(subAppId) } streamInfos := d.Get("stream_info").([]interface{}) request.StreamInfos = make([]*vod.AdaptiveStreamTemplate, 0, len(streamInfos)) @@ -210,16 +281,39 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateCreate(d *schema.Res video := v["video"].([]interface{})[0].(map[string]interface{}) audio := v["audio"].([]interface{})[0].(map[string]interface{}) rAudio := REMOVE_AUDIO_TO_UNINT[v["remove_audio"].(bool)] + videoTemplateInfo := &vod.VideoTemplateInfo{ + Codec: helper.String(video["codec"].(string)), + Fps: helper.IntUint64(video["fps"].(int)), + Bitrate: helper.IntUint64(video["bitrate"].(int)), + ResolutionAdaptive: helper.String(RESOLUTION_ADAPTIVE_TO_STRING[video["resolution_adaptive"].(bool)]), + Width: helper.IntUint64(video["width"].(int)), + Height: helper.IntUint64(video["height"].(int)), + FillType: helper.String(video["fill_type"].(string)), + } + var rVideo uint64 + if v, ok := video["remove_video"]; ok && v.(bool) { + rVideo = REMOVE_AUDIO_TO_UNINT[v.(bool)] + } + if v, ok := video["vcrf"]; ok && v.(int) != 0 { + videoTemplateInfo.Vcrf = helper.IntUint64(v.(int)) + } + if v, ok := video["gop"]; ok { + videoTemplateInfo.Gop = helper.IntUint64(v.(int)) + } + if v, ok := video["preserve_hdr_switch"]; ok && v.(string) != "" { + videoTemplateInfo.PreserveHDRSwitch = helper.String(v.(string)) + } + if v, ok := video["codec_tag"]; ok && v.(string) != "" { + videoTemplateInfo.CodecTag = helper.String(v.(string)) + } + + var tehdConfig map[string]interface{} + if len(v["tehd_config"].([]interface{})) > 0 { + tehdConfig = v["tehd_config"].([]interface{})[0].(map[string]interface{}) + } request.StreamInfos = append(request.StreamInfos, &vod.AdaptiveStreamTemplate{ - Video: &vod.VideoTemplateInfo{ - Codec: helper.String(video["codec"].(string)), - Fps: helper.IntUint64(video["fps"].(int)), - Bitrate: helper.IntUint64(video["bitrate"].(int)), - ResolutionAdaptive: helper.String(RESOLUTION_ADAPTIVE_TO_STRING[video["resolution_adaptive"].(bool)]), - Width: helper.IntUint64(video["width"].(int)), - Height: helper.IntUint64(video["height"].(int)), - FillType: helper.String(video["fill_type"].(string)), - }, + + Video: videoTemplateInfo, Audio: &vod.AudioTemplateInfo{ Codec: helper.String(audio["codec"].(string)), Bitrate: helper.IntUint64(audio["bitrate"].(int)), @@ -227,6 +321,19 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateCreate(d *schema.Res AudioChannel: helper.Int64(VOD_AUDIO_CHANNEL_TYPE_TO_INT[audio["audio_channel"].(string)]), }, RemoveAudio: &rAudio, + RemoveVideo: &rVideo, + TEHDConfig: func() *vod.TEHDConfig { + if tehdConfig == nil { + return nil + } + tehd := &vod.TEHDConfig{ + Type: helper.String(tehdConfig["type"].(string)), + } + if v, ok := tehdConfig["max_video_bitrate"]; ok { + tehd.MaxVideoBitrate = helper.IntUint64(v.(int)) + } + return tehd + }(), }) } @@ -236,8 +343,13 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateCreate(d *schema.Res ratelimit.Check(request.GetAction()) response, err = meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVodClient().CreateAdaptiveDynamicStreamingTemplate(request) if err != nil { - log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), err.Error()) - return tccommon.RetryError(err) + if sdkError, ok := err.(*sdkErrors.TencentCloudSDKError); ok { + if sdkError.Code == "FailedOperation" && sdkError.Message == "invalid vod user" { + return resource.RetryableError(err) + } + } + log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), strconv.ErrRange.Error()) + return resource.NonRetryableError(err) } return nil }) @@ -247,7 +359,8 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateCreate(d *schema.Res if response == nil || response.Response == nil { return fmt.Errorf("for vod adaptive dynamic streaming template creation, response is nil") } - d.SetId(strconv.FormatUint(*response.Response.Definition, 10)) + resourceId += strconv.FormatUint(*response.Response.Definition, 10) + d.SetId(resourceId) return resourceTencentCloudVodAdaptiveDynamicStreamingTemplateRead(d, meta) } @@ -259,14 +372,21 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateRead(d *schema.Resou var ( logId = tccommon.GetLogId(tccommon.ContextNil) ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id = d.Id() - subAppId = d.Get("sub_app_id").(int) + subAppId int + definition string client = meta.(tccommon.ProviderMeta).GetAPIV3Conn() vodService = VodService{client: client} ) + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + } else { + definition = d.Id() + } // waiting for refreshing cache time.Sleep(30 * time.Second) - template, has, err := vodService.DescribeAdaptiveDynamicStreamingTemplatesById(ctx, id, subAppId) + template, has, err := vodService.DescribeAdaptiveDynamicStreamingTemplatesById(ctx, definition, subAppId) if err != nil { return err } @@ -296,6 +416,10 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateRead(d *schema.Resou "width": v.Video.Width, "height": v.Video.Height, "fill_type": v.Video.FillType, + "vcrf": v.Video.Vcrf, + "gop": v.Video.Gop, + "preserve_hdr_switch": v.Video.PreserveHDRSwitch, + "codec_tag": v.Video.CodecTag, }, }, "audio": []map[string]interface{}{ @@ -307,9 +431,24 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateRead(d *schema.Resou }, }, "remove_audio": *v.RemoveAudio == 1, + "remove_video": *v.RemoveVideo == 1, + "tehd_config": func() []map[string]interface{} { + if v.TEHDConfig == nil { + return nil + } + return []map[string]interface{}{ + { + "type": v.TEHDConfig.Type, + "max_video_bitrate": v.TEHDConfig.MaxVideoBitrate, + }, + } + }(), }) } _ = d.Set("stream_info", streamInfos) + if subAppId != 0 { + _ = d.Set("sub_app_id", subAppId) + } return nil } @@ -320,12 +459,33 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateUpdate(d *schema.Res var ( logId = tccommon.GetLogId(tccommon.ContextNil) request = vod.NewModifyAdaptiveDynamicStreamingTemplateRequest() - id = d.Id() changeFlag = false + subAppId int + definition string ) - idUint, _ := strconv.ParseUint(id, 0, 64) - request.Definition = &idUint + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + request.SubAppId = helper.IntUint64(subAppId) + } else { + definition = d.Id() + if v, ok := d.GetOk("sub_app_id"); ok { + request.SubAppId = helper.IntUint64(v.(int)) + } + } + + request.Definition = helper.StrToUint64Point(definition) + + immutableArgs := []string{"sub_app_id"} + + for _, v := range immutableArgs { + if d.HasChange(v) { + return fmt.Errorf("argument `%s` cannot be changed", v) + } + } + if d.HasChange("format") { changeFlag = true request.Format = helper.String(d.Get("format").(string)) @@ -346,10 +506,6 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateUpdate(d *schema.Res changeFlag = true request.Comment = helper.String(d.Get("comment").(string)) } - if d.HasChange("sub_app_id") { - changeFlag = true - request.SubAppId = helper.IntUint64(d.Get("sub_app_id").(int)) - } if d.HasChange("stream_info") { changeFlag = true streamInfos := d.Get("stream_info").([]interface{}) @@ -358,7 +514,15 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateUpdate(d *schema.Res v := item.(map[string]interface{}) video := v["video"].([]interface{})[0].(map[string]interface{}) audio := v["audio"].([]interface{})[0].(map[string]interface{}) + var tehdConfig map[string]interface{} + if len(v["tehd_config"].([]interface{})) > 0 { + tehdConfig = v["tehd_config"].([]interface{})[0].(map[string]interface{}) + } rAudio := REMOVE_AUDIO_TO_UNINT[v["remove_audio"].(bool)] + var rVideo uint64 + if v, ok := video["remove_video"]; ok && v.(bool) { + rVideo = REMOVE_AUDIO_TO_UNINT[v.(bool)] + } request.StreamInfos = append(request.StreamInfos, &vod.AdaptiveStreamTemplate{ Video: &vod.VideoTemplateInfo{ Codec: helper.String(video["codec"].(string)), @@ -378,6 +542,30 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateUpdate(d *schema.Res return helper.IntUint64(height) }(video["height"].(int)), FillType: helper.String(video["fill_type"].(string)), + Vcrf: func() *uint64 { + if v, ok := video["vcrf"]; !ok || v.(int) == 0 { + return nil + } + return helper.IntUint64(video["vcrf"].(int)) + }(), + Gop: func() *uint64 { + if _, ok := video["gop"]; !ok { + return nil + } + return helper.IntUint64(video["gop"].(int)) + }(), + PreserveHDRSwitch: func() *string { + if v, ok := video["preserve_hdr_switch"]; !ok || v.(string) == "" { + return nil + } + return helper.String(video["preserve_hdr_switch"].(string)) + }(), + CodecTag: func() *string { + if v, ok := video["codec_tag"]; !ok || v.(string) == "" { + return nil + } + return helper.String(video["codec_tag"].(string)) + }(), }, Audio: &vod.AudioTemplateInfo{ Codec: helper.String(audio["codec"].(string)), @@ -386,6 +574,19 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateUpdate(d *schema.Res AudioChannel: helper.Int64(VOD_AUDIO_CHANNEL_TYPE_TO_INT[audio["audio_channel"].(string)]), }, RemoveAudio: &rAudio, + RemoveVideo: &rVideo, + TEHDConfig: func() *vod.TEHDConfig { + if tehdConfig == nil { + return nil + } + tehd := &vod.TEHDConfig{ + Type: helper.String(tehdConfig["type"].(string)), + } + if v, ok := tehdConfig["max_video_bitrate"]; ok { + tehd.MaxVideoBitrate = helper.IntUint64(v.(int)) + } + return tehd + }(), }) } } @@ -417,12 +618,25 @@ func resourceTencentCloudVodAdaptiveDynamicStreamingTemplateDelete(d *schema.Res logId := tccommon.GetLogId(tccommon.ContextNil) ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id := d.Id() + var ( + subAppId int + definition string + ) + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + } else { + definition = d.Id() + if v, ok := d.GetOk("sub_app_id"); ok { + subAppId = v.(int) + } + } vodService := VodService{ client: meta.(tccommon.ProviderMeta).GetAPIV3Conn(), } - if err := vodService.DeleteAdaptiveDynamicStreamingTemplate(ctx, id, uint64(d.Get("sub_app_id").(int))); err != nil { + if err := vodService.DeleteAdaptiveDynamicStreamingTemplate(ctx, definition, uint64(subAppId)); err != nil { return err } diff --git a/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.md b/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.md index 487b9c6c04..7644293cea 100644 --- a/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.md +++ b/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template.md @@ -3,52 +3,44 @@ Provide a resource to create a VOD adaptive dynamic streaming template. Example Usage ```hcl +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "adaptive-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { format = "HLS" name = "tf-adaptive" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) drm_type = "SimpleAES" disable_higher_video_bitrate = false disable_higher_video_resolution = false comment = "test" - stream_info { - video { - codec = "libx265" - fps = 4 - bitrate = 129 - resolution_adaptive = false - width = 128 - height = 128 - fill_type = "stretch" - } - audio { - codec = "libmp3lame" - bitrate = 129 - sample_rate = 44100 - audio_channel = "dual" - } - remove_audio = false - } stream_info { video { codec = "libx264" - fps = 4 - bitrate = 256 + fps = 3 + bitrate = 128 } audio { codec = "libfdk_aac" - bitrate = 256 - sample_rate = 44100 + bitrate = 128 + sample_rate = 32000 } remove_audio = true + tehd_config { + type = "TEHD-100" + } } } ``` Import -VOD adaptive dynamic streaming template can be imported using the id, e.g. +VOD adaptive dynamic streaming template can be imported using the id($subAppId#$templateId), e.g. ``` -$ terraform import tencentcloud_vod_adaptive_dynamic_streaming_template.foo 169141 +$ terraform import tencentcloud_vod_adaptive_dynamic_streaming_template.foo $subAppId#$templateId ``` \ No newline at end of file diff --git a/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template_test.go b/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template_test.go index 7ab4ae3b60..59ec1ec241 100644 --- a/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template_test.go +++ b/tencentcloud/services/vod/resource_tc_vod_adaptive_dynamic_streaming_template_test.go @@ -4,10 +4,12 @@ import ( "context" "fmt" "strconv" + "strings" "testing" tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" svcvod "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/services/vod" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -53,7 +55,6 @@ func TestAccTencentCloudVodAdaptiveDynamicStreamingTemplateResource(t *testing.T { Config: testAccVodAdaptiveDynamicStreamingTemplate, Check: resource.ComposeTestCheckFunc( - testAccCheckVodAdaptiveDynamicStreamingTemplateExists("tencentcloud_vod_adaptive_dynamic_streaming_template.foo"), resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "format", "HLS"), resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "name", "tf-adaptive"), resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "drm_type", "SimpleAES"), @@ -81,6 +82,7 @@ func TestAccTencentCloudVodAdaptiveDynamicStreamingTemplateResource(t *testing.T resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "stream_info.1.remove_audio", "true"), resource.TestCheckResourceAttrSet("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "create_time"), resource.TestCheckResourceAttrSet("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "update_time"), + resource.TestCheckResourceAttrSet("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "sub_app_id"), ), }, { @@ -104,13 +106,14 @@ func TestAccTencentCloudVodAdaptiveDynamicStreamingTemplateResource(t *testing.T resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "stream_info.0.audio.0.sample_rate", "44100"), resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "stream_info.0.audio.0.audio_channel", "dual"), resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "stream_info.0.remove_audio", "false"), + resource.TestCheckResourceAttrSet("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "sub_app_id"), + resource.TestCheckResourceAttr("tencentcloud_vod_adaptive_dynamic_streaming_template.foo", "stream_info.0.tehd_config.0.type", "TEHD-100"), ), }, { - ResourceName: "tencentcloud_vod_adaptive_dynamic_streaming_template.foo", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"sub_app_id"}, + ResourceName: "tencentcloud_vod_adaptive_dynamic_streaming_template.foo", + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -125,11 +128,13 @@ func testAccCheckVodAdaptiveDynamicStreamingTemplateDestroy(s *terraform.State) if rs.Type != "tencentcloud_vod_adaptive_dynamic_streaming_template" { continue } - var ( - filter = map[string]interface{}{ - "definitions": []string{rs.Primary.ID}, - } - ) + idSplit := strings.Split(rs.Primary.ID, tccommon.FILED_SP) + subAppId := helper.StrToInt(idSplit[0]) + definition := idSplit[1] + filter := map[string]interface{}{ + "definitions": []string{definition}, + "sub_appid": subAppId, + } templates, err := vodService.DescribeAdaptiveDynamicStreamingTemplatesByFilter(ctx, filter) if err != nil { @@ -156,9 +161,13 @@ func testAccCheckVodAdaptiveDynamicStreamingTemplateExists(n string) resource.Te return fmt.Errorf("vod adaptive dynamic streaming template id is not set") } vodService := svcvod.NewVodService(tcacctest.AccProvider.Meta().(tccommon.ProviderMeta).GetAPIV3Conn()) + idSplit := strings.Split(rs.Primary.ID, tccommon.FILED_SP) + subAppId := helper.StrToInt(idSplit[0]) + definition := idSplit[1] var ( filter = map[string]interface{}{ - "definitions": []string{rs.Primary.ID}, + "definitions": []string{definition}, + "sub_appid": subAppId, } ) @@ -174,9 +183,16 @@ func testAccCheckVodAdaptiveDynamicStreamingTemplateExists(n string) resource.Te } const testAccVodAdaptiveDynamicStreamingTemplate = ` +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "adaptive-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { format = "HLS" name = "tf-adaptive" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) drm_type = "SimpleAES" disable_higher_video_bitrate = false disable_higher_video_resolution = false @@ -212,9 +228,16 @@ resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { ` const testAccVodAdaptiveDynamicStreamingTemplateUpdate = ` +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "adaptive-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { format = "HLS" name = "tf-adaptive-update" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) drm_type = "SimpleAES" disable_higher_video_bitrate = true disable_higher_video_resolution = true @@ -237,6 +260,9 @@ resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { audio_channel = "dual" } remove_audio = false + tehd_config { + type = "TEHD-100" + } } } ` diff --git a/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.go b/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.go index bfa6c9fb0f..82c44a5143 100644 --- a/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.go +++ b/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.go @@ -5,12 +5,14 @@ import ( "fmt" "log" "strconv" + "strings" "time" tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" vod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod/v20180717" "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" @@ -88,7 +90,17 @@ func ResourceTencentCloudVodImageSpriteTemplate() *schema.Resource { "sub_app_id": { Type: schema.TypeInt, Optional: true, - Description: "Subapplication ID in VOD. If you need to access a resource in a subapplication, enter the subapplication ID in this field; otherwise, leave it empty.", + Description: "The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID.", + }, + "format": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Image format, Valid values:\n" + + "- jpg: jpg format;\n" + + "- png: png format;\n" + + "- webp: webp format;\n" + + "Default value: jpg.", }, // computed "create_time": { @@ -101,6 +113,13 @@ func ResourceTencentCloudVodImageSpriteTemplate() *schema.Resource { Computed: true, Description: "Last modified time of template in ISO date format.", }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Template type, value range:\n" + + "- Preset: system preset template;\n" + + "- Custom: user-defined templates.", + }, }, } } @@ -125,8 +144,15 @@ func resourceTencentCloudVodImageSpriteTemplateCreate(d *schema.ResourceData, me request.Width = helper.IntUint64(d.Get("width").(int)) request.Height = helper.IntUint64(d.Get("height").(int)) request.ResolutionAdaptive = helper.String(RESOLUTION_ADAPTIVE_TO_STRING[d.Get("resolution_adaptive").(bool)]) + var resourceId string if v, ok := d.GetOk("sub_app_id"); ok { - request.SubAppId = helper.IntUint64(v.(int)) + subAppId := v.(int) + resourceId += helper.IntToStr(subAppId) + resourceId += tccommon.FILED_SP + request.SubAppId = helper.IntUint64(subAppId) + } + if v, ok := d.GetOk("format"); ok { + request.Format = helper.String(v.(string)) } var response *vod.CreateImageSpriteTemplateResponse @@ -135,8 +161,13 @@ func resourceTencentCloudVodImageSpriteTemplateCreate(d *schema.ResourceData, me ratelimit.Check(request.GetAction()) response, err = meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVodClient().CreateImageSpriteTemplate(request) if err != nil { + if sdkError, ok := err.(*sdkErrors.TencentCloudSDKError); ok { + if sdkError.Code == "FailedOperation" && sdkError.Message == "invalid vod user" { + return resource.RetryableError(err) + } + } log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), err.Error()) - return tccommon.RetryError(err) + return resource.NonRetryableError(err) } return nil }) @@ -146,7 +177,8 @@ func resourceTencentCloudVodImageSpriteTemplateCreate(d *schema.ResourceData, me if response == nil || response.Response == nil { return fmt.Errorf("for image sprite template creation, response is nil") } - d.SetId(strconv.FormatUint(*response.Response.Definition, 10)) + resourceId += strconv.FormatUint(*response.Response.Definition, 10) + d.SetId(resourceId) return resourceTencentCloudVodImageSpriteTemplateRead(d, meta) } @@ -158,14 +190,21 @@ func resourceTencentCloudVodImageSpriteTemplateRead(d *schema.ResourceData, meta var ( logId = tccommon.GetLogId(tccommon.ContextNil) ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id = d.Id() - subAppId = d.Get("sub_app_id").(int) + subAppId int + definition string client = meta.(tccommon.ProviderMeta).GetAPIV3Conn() vodService = VodService{client: client} ) + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + } else { + definition = d.Id() + } // waiting for refreshing cache time.Sleep(30 * time.Second) - template, has, err := vodService.DescribeImageSpriteTemplatesById(ctx, id, subAppId) + template, has, err := vodService.DescribeImageSpriteTemplatesById(ctx, definition, subAppId) if err != nil { return err } @@ -186,6 +225,11 @@ func resourceTencentCloudVodImageSpriteTemplateRead(d *schema.ResourceData, meta _ = d.Set("resolution_adaptive", *template.ResolutionAdaptive == "open") _ = d.Set("create_time", template.CreateTime) _ = d.Set("update_time", template.UpdateTime) + _ = d.Set("format", template.Format) + _ = d.Set("type", template.Type) + if subAppId != 0 { + _ = d.Set("sub_app_id", subAppId) + } return nil } @@ -196,12 +240,31 @@ func resourceTencentCloudVodImageSpriteTemplateUpdate(d *schema.ResourceData, me var ( logId = tccommon.GetLogId(tccommon.ContextNil) request = vod.NewModifyImageSpriteTemplateRequest() - id = d.Id() changeFlag = false + subAppId int + definition string ) - idUint, _ := strconv.ParseUint(id, 0, 64) - request.Definition = &idUint + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + request.SubAppId = helper.IntUint64(subAppId) + } else { + definition = d.Id() + if v, ok := d.GetOk("sub_app_id"); ok { + request.SubAppId = helper.IntUint64(v.(int)) + } + } + request.Definition = helper.StrToUint64Point(definition) + immutableArgs := []string{"sub_app_id"} + + for _, v := range immutableArgs { + if d.HasChange(v) { + return fmt.Errorf("argument `%s` cannot be changed", v) + } + } + if d.HasChange("sample_type") { changeFlag = true request.SampleType = helper.String(d.Get("sample_type").(string)) @@ -236,9 +299,9 @@ func resourceTencentCloudVodImageSpriteTemplateUpdate(d *schema.ResourceData, me request.Height = helper.IntUint64(d.Get("height").(int)) request.ResolutionAdaptive = helper.String(RESOLUTION_ADAPTIVE_TO_STRING[d.Get("resolution_adaptive").(bool)]) } - if d.HasChange("sub_app_id") { + if d.HasChange("format") { changeFlag = true - request.SubAppId = helper.IntUint64(d.Get("sub_app_id").(int)) + request.Format = helper.String(d.Get("format").(string)) } if changeFlag { @@ -268,12 +331,25 @@ func resourceTencentCloudVodImageSpriteTemplateDelete(d *schema.ResourceData, me logId := tccommon.GetLogId(tccommon.ContextNil) ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id := d.Id() + var ( + subAppId int + definition string + ) + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + } else { + definition = d.Id() + if v, ok := d.GetOk("sub_app_id"); ok { + subAppId = v.(int) + } + } vodService := VodService{ client: meta.(tccommon.ProviderMeta).GetAPIV3Conn(), } - if err := vodService.DeleteImageSpriteTemplate(ctx, id, uint64(d.Get("sub_app_id").(int))); err != nil { + if err := vodService.DeleteImageSpriteTemplate(ctx, definition, uint64(subAppId)); err != nil { return err } diff --git a/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.md b/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.md index d40212a128..75f64e9ce5 100644 --- a/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.md +++ b/tencentcloud/services/vod/resource_tc_vod_image_sprite_template.md @@ -3,8 +3,15 @@ Provide a resource to create a VOD image sprite template. Example Usage ```hcl +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "image-sprite-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_image_sprite_template" "foo" { sample_type = "Percent" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) sample_interval = 10 row_count = 3 column_count = 3 @@ -19,8 +26,8 @@ resource "tencentcloud_vod_image_sprite_template" "foo" { Import -VOD image sprite template can be imported using the id, e.g. +VOD image sprite template can be imported using the id($subAppId#$templateId), e.g. ``` -$ terraform import tencentcloud_vod_image_sprite_template.foo 51156 +$ terraform import tencentcloud_vod_image_sprite_template.foo $subAppId#$templateId ``` \ No newline at end of file diff --git a/tencentcloud/services/vod/resource_tc_vod_image_sprite_template_test.go b/tencentcloud/services/vod/resource_tc_vod_image_sprite_template_test.go index 23b5cf0805..3a1fc1624d 100644 --- a/tencentcloud/services/vod/resource_tc_vod_image_sprite_template_test.go +++ b/tencentcloud/services/vod/resource_tc_vod_image_sprite_template_test.go @@ -3,10 +3,12 @@ package vod_test import ( "context" "fmt" + "strings" "testing" tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" svcvod "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/services/vod" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -23,7 +25,6 @@ func TestAccTencentCloudVodImageSpriteTemplateResource(t *testing.T) { { Config: testAccVodImageSpriteTemplate, Check: resource.ComposeTestCheckFunc( - testAccCheckVodImageSpriteTemplateExists("tencentcloud_vod_image_sprite_template.foo"), resource.TestCheckResourceAttr("tencentcloud_vod_image_sprite_template.foo", "sample_type", "Percent"), resource.TestCheckResourceAttr("tencentcloud_vod_image_sprite_template.foo", "sample_interval", "10"), resource.TestCheckResourceAttr("tencentcloud_vod_image_sprite_template.foo", "row_count", "3"), @@ -34,8 +35,10 @@ func TestAccTencentCloudVodImageSpriteTemplateResource(t *testing.T) { resource.TestCheckResourceAttr("tencentcloud_vod_image_sprite_template.foo", "width", "128"), resource.TestCheckResourceAttr("tencentcloud_vod_image_sprite_template.foo", "height", "128"), resource.TestCheckResourceAttr("tencentcloud_vod_image_sprite_template.foo", "resolution_adaptive", "false"), + resource.TestCheckResourceAttr("tencentcloud_vod_image_sprite_template.foo", "format", "jpg"), resource.TestCheckResourceAttrSet("tencentcloud_vod_image_sprite_template.foo", "create_time"), resource.TestCheckResourceAttrSet("tencentcloud_vod_image_sprite_template.foo", "update_time"), + resource.TestCheckResourceAttrSet("tencentcloud_vod_image_sprite_template.foo", "type"), ), }, { @@ -54,10 +57,9 @@ func TestAccTencentCloudVodImageSpriteTemplateResource(t *testing.T) { ), }, { - ResourceName: "tencentcloud_vod_image_sprite_template.foo", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"sub_app_id"}, + ResourceName: "tencentcloud_vod_image_sprite_template.foo", + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -72,9 +74,13 @@ func testAccCheckVodImageSpriteTemplateDestroy(s *terraform.State) error { if rs.Type != "tencentcloud_vod_image_sprite_template" { continue } + idSplit := strings.Split(rs.Primary.ID, tccommon.FILED_SP) + subAppId := helper.StrToInt(idSplit[0]) + definition := idSplit[1] var ( filter = map[string]interface{}{ - "definitions": []string{rs.Primary.ID}, + "definitions": []string{definition}, + "sub_appid": subAppId, } ) @@ -103,9 +109,13 @@ func testAccCheckVodImageSpriteTemplateExists(n string) resource.TestCheckFunc { return fmt.Errorf("vod image sprite template id is not set") } vodService := svcvod.NewVodService(tcacctest.AccProvider.Meta().(tccommon.ProviderMeta).GetAPIV3Conn()) + idSplit := strings.Split(rs.Primary.ID, tccommon.FILED_SP) + subAppId := helper.StrToInt(idSplit[0]) + definition := idSplit[1] var ( filter = map[string]interface{}{ - "definitions": []string{rs.Primary.ID}, + "definitions": []string{definition}, + "sub_appid": subAppId, } ) templates, err := vodService.DescribeImageSpriteTemplatesByFilter(ctx, filter) @@ -120,8 +130,15 @@ func testAccCheckVodImageSpriteTemplateExists(n string) resource.TestCheckFunc { } const testAccVodImageSpriteTemplate = ` +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "image-sprite-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_image_sprite_template" "foo" { sample_type = "Percent" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) sample_interval = 10 row_count = 3 column_count = 3 @@ -135,8 +152,15 @@ resource "tencentcloud_vod_image_sprite_template" "foo" { ` const testAccVodImageSpriteTemplateUpdate = ` +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "image-sprite-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_image_sprite_template" "foo" { sample_type = "Time" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) sample_interval = 11 row_count = 4 column_count = 4 diff --git a/tencentcloud/services/vod/resource_tc_vod_procedure_template.go b/tencentcloud/services/vod/resource_tc_vod_procedure_template.go index 7fb8897cea..b0e8aaa928 100644 --- a/tencentcloud/services/vod/resource_tc_vod_procedure_template.go +++ b/tencentcloud/services/vod/resource_tc_vod_procedure_template.go @@ -2,6 +2,7 @@ package vod import ( "context" + "fmt" "log" "strconv" "strings" @@ -43,7 +44,7 @@ func ResourceTencentCloudVodProcedureTemplate() *schema.Resource { "sub_app_id": { Type: schema.TypeInt, Optional: true, - Description: "Subapplication ID in VOD. For customers who activate VOD from December 25, 2023, if they access the resources in the VOD application (whether it is the default application or the newly created application), you must fill in this field as Application ID.", + Description: "The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID.", }, "media_process_task": { Type: schema.TypeList, @@ -121,6 +122,68 @@ func ResourceTencentCloudVodProcedureTemplate() *schema.Resource { }, }, }, + "trace_watermark": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "Digital watermark.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "switch": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Whether to use digital watermarks. This parameter is required. Valid values: ON, OFF.", + }, + }, + }, + }, + "copy_right_watermark": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "opyright watermark.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "text": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Copyright information, maximum length is 200 characters.", + }, + }, + }, + }, + "head_tail_list": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "List of video opening/closing credits configuration template IDs. You can enter up to 10 IDs.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "definition": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Video opening/closing credits configuration template ID.", + }, + }, + }, + }, + "start_time_offset": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "Start time offset of blur in seconds. If this parameter is left empty or `0` is entered, the blur will appear upon the first video frame. If this parameter is left empty or `0` is entered, the blur will appear upon the first video frame; If this value is greater than `0` (e.g., n), the blur will appear at second n after the first video frame; If this value is smaller than `0` (e.g., -n), the blur will appear at second n before the last video frame.", + }, + "end_time_offset": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + Description: "End time offset of blur in seconds. If this parameter is left empty or `0` is entered, the blur will exist till the last video frame; If this value is greater than `0` (e.g., n), the blur will exist till second n; If this value is smaller than `0` (e.g., -n), the blur will exist till second n before the last video frame.", + }, }, }, }, @@ -174,6 +237,15 @@ func ResourceTencentCloudVodProcedureTemplate() *schema.Resource { Description: "List of up to `10` image or text watermarks. Note: this field may return null, indicating that no valid values can be obtained.", Elem: VodWatermarkResource(), }, + "time_offset_list": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "List of time points for screencapturing in milliseconds. Note: this field may return null, indicating that no valid values can be obtained.", + Elem: &schema.Schema{ + Type: schema.TypeFloat, + }, + }, }, }, }, @@ -268,6 +340,62 @@ func ResourceTencentCloudVodProcedureTemplate() *schema.Resource { }, }, }, + "ai_analysis_task": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "Parameter of AI-based content analysis task.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "definition": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Video content analysis template ID.", + }, + }, + }, + }, + "ai_recognition_task": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "Type parameter of AI-based content recognition task.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "definition": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Intelligent video recognition template ID.", + }, + }, + }, + }, + "review_audio_video_task": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: "Type parameter of AI-based content recognition task.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "review_contents": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "The type of moderated content. Valid values:\n" + + "- `Media`: The original audio/video;\n" + + "- `Cover`: Thumbnails.", + }, + }, + }, + }, "create_time": { Type: schema.TypeString, Computed: true, @@ -278,6 +406,13 @@ func ResourceTencentCloudVodProcedureTemplate() *schema.Resource { Computed: true, Description: "Last modified time of template in ISO date format.", }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Template type, value range:\n" + + "- Preset: system preset template;\n" + + "- Custom: user-defined templates.", + }, }, } } @@ -407,6 +542,68 @@ func generateMediaProcessTask(d *schema.ResourceData) (mediaReq *vod.MediaProces }(item["definition"].(string)), WatermarkSet: genWatermarkList(item), MosaicSet: genMosaicList(item), + TraceWatermark: func() *vod.TraceWatermarkInput { + if _, ok := item["trace_watermark"]; !ok { + return nil + } + traceWatermarks := item["trace_watermark"].([]interface{}) + if len(traceWatermarks) <= 0 { + return nil + } + traceWatermarkInput := &vod.TraceWatermarkInput{} + traceWatermarkItem := traceWatermarks[0].(map[string]interface{}) + if v, ok := traceWatermarkItem["switch"]; ok { + traceWatermarkInput.Switch = helper.String(v.(string)) + } + return traceWatermarkInput + }(), + CopyRightWatermark: func() *vod.CopyRightWatermarkInput { + if _, ok := item["copy_right_watermark"]; !ok { + return nil + } + copyRightWatermarks := item["copy_right_watermark"].([]interface{}) + if len(copyRightWatermarks) <= 0 { + return nil + } + + copyRightWatermarkInput := &vod.CopyRightWatermarkInput{} + copyRightWatermarkItem := copyRightWatermarks[0].(map[string]interface{}) + if vv, ok := copyRightWatermarkItem["text"]; ok { + copyRightWatermarkInput = &vod.CopyRightWatermarkInput{ + Text: helper.String(vv.(string)), + } + } + return copyRightWatermarkInput + }(), + HeadTailSet: func() (list []*vod.HeadTailTaskInput) { + if _, ok := item["head_tail_list"]; !ok { + return + } + headTailSet := item["head_tail_list"].([]interface{}) + list = make([]*vod.HeadTailTaskInput, 0, len(headTailSet)) + for _, headTail := range headTailSet { + headTailMap := headTail.(map[string]interface{}) + list = append(list, &vod.HeadTailTaskInput{ + Definition: func(str string) *int64 { + definition, _ := strconv.ParseInt(str, 0, 64) + return &definition + }(headTailMap["definition"].(string)), + }) + } + return + }(), + StartTimeOffset: func() *float64 { + if _, ok := item["start_time_offset"]; !ok { + return nil + } + return helper.Float64(item["start_time_offset"].(float64)) + }(), + EndTimeOffset: func() *float64 { + if _, ok := item["end_time_offset"]; !ok { + return nil + } + return helper.Float64(item["end_time_offset"].(float64)) + }(), }) } mediaReq.TranscodeTaskSet = transcodeReq @@ -451,6 +648,17 @@ func generateMediaProcessTask(d *schema.ResourceData) (mediaReq *vod.MediaProces } return list }(), + TimeOffsetSet: func() (list []*float64) { + if _, ok := item["time_offset_list"]; !ok { + return nil + } + timeOffsetSet := item["time_offset_list"].([]interface{}) + list = make([]*float64, 0, len(timeOffsetSet)) + for _, timeOffset := range timeOffsetSet { + list = append(list, helper.Float64(timeOffset.(float64))) + } + return list + }(), }) } mediaReq.SnapshotByTimeOffsetTaskSet = snapshotReq @@ -549,7 +757,44 @@ func resourceTencentCloudVodProcedureTemplateCreate(d *schema.ResourceData, meta mediaReq := generateMediaProcessTask(d) request.MediaProcessTask = mediaReq } + //ai_analysis_task + if aiAnalysisTask, ok := d.GetOk("ai_analysis_task"); ok { + aiAnalysisTaskList := aiAnalysisTask.([]interface{}) + aiAnalysisTaskItem := aiAnalysisTaskList[0].(map[string]interface{}) + + request.AiAnalysisTask = &vod.AiAnalysisTaskInput{ + Definition: helper.StrToUint64Point(aiAnalysisTaskItem["definition"].(string)), + } + } + //ai_recognition_task + if aiRecognitionTask, ok := d.GetOk("ai_recognition_task"); ok { + aiRecognitionTaskList := aiRecognitionTask.([]interface{}) + aiRecognitionTaskItem := aiRecognitionTaskList[0].(map[string]interface{}) + + request.AiRecognitionTask = &vod.AiRecognitionTaskInput{ + Definition: helper.StrToUint64Point(aiRecognitionTaskItem["definition"].(string)), + } + } + //review_audio_video_task + if reviewAudioVideoTask, ok := d.GetOk("review_audio_video_task"); ok { + reviewAudioVideoTaskList := reviewAudioVideoTask.([]interface{}) + reviewAudioVideoTaskItem := reviewAudioVideoTaskList[0].(map[string]interface{}) + request.ReviewAudioVideoTask = &vod.ProcedureReviewAudioVideoTaskInput{ + Definition: helper.StrToUint64Point(reviewAudioVideoTaskItem["definition"].(string)), + ReviewContents: func() (list []*string) { + if _, ok := reviewAudioVideoTaskItem["review_contents"]; !ok { + return + } + reviewContentList := reviewAudioVideoTaskItem["review_contents"].([]interface{}) + list = make([]*string, 0, len(reviewContentList)) + for _, reviewContent := range reviewContentList { + list = append(list, helper.String(reviewContent.(string))) + } + return + }(), + } + } var err error err = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { ratelimit.Check(request.GetAction()) @@ -599,6 +844,7 @@ func resourceTencentCloudVodProcedureTemplateRead(d *schema.ResourceData, meta i } _ = d.Set("name", template.Name) + _ = d.Set("type", template.Type) _ = d.Set("comment", template.Comment) _ = d.Set("create_time", template.CreateTime) _ = d.Set("update_time", template.UpdateTime) @@ -648,6 +894,48 @@ func resourceTencentCloudVodProcedureTemplateRead(d *schema.ResourceData, meta i } return mosaicList }(), + "trace_watermark": func() interface{} { + if item.TraceWatermark == nil { + return nil + } + traceWatermark := map[string]interface{}{ + "switch": item.TraceWatermark.Switch, + } + return []interface{}{traceWatermark} + }(), + "copy_right_watermark": func() interface{} { + if item.CopyRightWatermark == nil { + return nil + } + copyRightWatermark := map[string]interface{}{ + "text": item.CopyRightWatermark.Text, + } + return []interface{}{copyRightWatermark} + }(), + "head_tail_list": func() interface{} { + if item.HeadTailSet == nil { + return nil + } + headTailList := make([]interface{}, 0, len(item.HeadTailSet)) + for _, headTail := range item.HeadTailSet { + headTailList = append(headTailList, map[string]interface{}{ + "definition": headTail.Definition, + }) + } + return headTailList + }(), + "start_time_offset": func() *float64 { + if item.StartTimeOffset == nil { + return nil + } + return item.StartTimeOffset + }(), + "end_time_offset": func() *float64 { + if item.EndTimeOffset == nil { + return nil + } + return item.EndTimeOffset + }(), }) } mediaProcessTaskElem["transcode_task_list"] = list @@ -696,6 +984,16 @@ func resourceTencentCloudVodProcedureTemplateRead(d *schema.ResourceData, meta i } return extList }(), + "time_offset_list": func() interface{} { + if item.TimeOffsetSet == nil { + return nil + } + timeOffsetList := make([]interface{}, 0, len(item.TimeOffsetSet)) + for _, timeOffset := range item.TimeOffsetSet { + timeOffsetList = append(timeOffsetList, timeOffset) + } + return timeOffsetList + }(), }) } mediaProcessTaskElem["snapshot_by_time_offset_task_list"] = list @@ -793,7 +1091,30 @@ func resourceTencentCloudVodProcedureTemplateRead(d *schema.ResourceData, meta i _ = d.Set("media_process_task", []interface{}{mediaProcessTaskElem}) } - + aiAnalysisTask := make(map[string]interface{}) + if template.AiAnalysisTask != nil && template.AiAnalysisTask.Definition != nil { + aiAnalysisTask["definition"] = template.AiAnalysisTask.Definition + } + _ = d.Set("ai_analysis_task", []interface{}{aiAnalysisTask}) + aiRecognitionTask := make(map[string]interface{}) + if template.AiRecognitionTask != nil && template.AiRecognitionTask.Definition != nil { + aiRecognitionTask["definition"] = template.AiRecognitionTask.Definition + } + _ = d.Set("ai_recognition_task", []interface{}{aiRecognitionTask}) + reviewAudioVideoTask := make(map[string]interface{}) + if template.ReviewAudioVideoTask != nil { + if template.ReviewAudioVideoTask.Definition != nil { + reviewAudioVideoTask["definition"] = template.ReviewAudioVideoTask.Definition + } + if template.ReviewAudioVideoTask.ReviewContents != nil { + reviewContentList := make([]string, 0, len(template.ReviewAudioVideoTask.ReviewContents)) + for _, revireviewContent := range template.ReviewAudioVideoTask.ReviewContents { + reviewContentList = append(reviewContentList, *revireviewContent) + } + reviewAudioVideoTask["review_contents"] = reviewContentList + } + } + _ = d.Set("review_audio_video_task", []interface{}{reviewAudioVideoTask}) return nil } @@ -819,6 +1140,14 @@ func resourceTencentCloudVodProcedureTemplateUpdate(d *schema.ResourceData, meta } } + immutableArgs := []string{"sub_app_id"} + + for _, v := range immutableArgs { + if d.HasChange(v) { + return fmt.Errorf("argument `%s` cannot be changed", v) + } + } + if d.HasChange("comment") { changeFlag = true request.Comment = helper.String(d.Get("comment").(string)) @@ -830,6 +1159,51 @@ func resourceTencentCloudVodProcedureTemplateUpdate(d *schema.ResourceData, meta request.MediaProcessTask = mediaReq } + if d.HasChange("ai_analysis_task") { + changeFlag = true + if aiAnalysisTask, ok := d.GetOk("ai_analysis_task"); ok { + aiAnalysisTaskList := aiAnalysisTask.([]interface{}) + aiAnalysisTaskItem := aiAnalysisTaskList[0].(map[string]interface{}) + + request.AiAnalysisTask = &vod.AiAnalysisTaskInput{ + Definition: helper.StrToUint64Point(aiAnalysisTaskItem["definition"].(string)), + } + } + } + + if d.HasChange("ai_recognition_task") { + changeFlag = true + if aiRecognitionTask, ok := d.GetOk("ai_recognition_task"); ok { + aiRecognitionTaskList := aiRecognitionTask.([]interface{}) + aiRecognitionTaskItem := aiRecognitionTaskList[0].(map[string]interface{}) + + request.AiRecognitionTask = &vod.AiRecognitionTaskInput{ + Definition: helper.StrToUint64Point(aiRecognitionTaskItem["definition"].(string)), + } + } + } + if d.HasChange("review_audio_video_task") { + changeFlag = true + if reviewAudioVideoTask, ok := d.GetOk("review_audio_video_task"); ok { + reviewAudioVideoTaskList := reviewAudioVideoTask.([]interface{}) + reviewAudioVideoTaskItem := reviewAudioVideoTaskList[0].(map[string]interface{}) + request.ReviewAudioVideoTask = &vod.ProcedureReviewAudioVideoTaskInput{ + Definition: helper.StrToUint64Point(reviewAudioVideoTaskItem["definition"].(string)), + ReviewContents: func() (list []*string) { + if _, ok := reviewAudioVideoTaskItem["review_contents"]; !ok { + return + } + reviewContentList := reviewAudioVideoTaskItem["review_contents"].([]interface{}) + list = make([]*string, 0, len(reviewContentList)) + for _, reviewContent := range reviewContentList { + list = append(list, helper.String(reviewContent.(string))) + } + return + }(), + } + } + } + if changeFlag { var err error err = resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { diff --git a/tencentcloud/services/vod/resource_tc_vod_procedure_template.md b/tencentcloud/services/vod/resource_tc_vod_procedure_template.md index 8ba2f1a452..0cff89e197 100644 --- a/tencentcloud/services/vod/resource_tc_vod_procedure_template.md +++ b/tencentcloud/services/vod/resource_tc_vod_procedure_template.md @@ -3,9 +3,16 @@ Provide a resource to create a VOD procedure template. Example Usage ```hcl +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "procedure-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { format = "HLS" name = "tf-adaptive" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) drm_type = "SimpleAES" disable_higher_video_bitrate = false disable_higher_video_resolution = false @@ -13,21 +20,16 @@ resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { stream_info { video { - codec = "libx265" - fps = 4 - bitrate = 129 - resolution_adaptive = false - width = 128 - height = 128 - fill_type = "stretch" + codec = "libx264" + fps = 3 + bitrate = 128 } audio { - codec = "libmp3lame" - bitrate = 129 - sample_rate = 44100 - audio_channel = "dual" + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 32000 } - remove_audio = false + remove_audio = true } stream_info { video { @@ -41,12 +43,16 @@ resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { sample_rate = 44100 } remove_audio = true + tehd_config { + type = "TEHD-100" + } } } resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { name = "tf-snapshot" - width = 130 + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + width = 128 height = 128 resolution_adaptive = false format = "png" @@ -56,6 +62,7 @@ resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { resource "tencentcloud_vod_image_sprite_template" "foo" { sample_type = "Percent" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) sample_interval = 10 row_count = 3 column_count = 3 @@ -67,28 +74,56 @@ resource "tencentcloud_vod_image_sprite_template" "foo" { resolution_adaptive = false } -resource "tencentcloud_vod_sub_application" "sub_application" { - name = "subapplication" - status = "On" - description = "this is sub application" +resource "tencentcloud_vod_transcode_template" "transcode_template" { + container = "mp4" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + name = "720pTranscodeTemplate" + comment = "test transcode mp4 720p update" + remove_video = 0 + remove_audio = 0 + video_template { + codec = "libx264" + fps = 26 + bitrate = 1000 + resolution_adaptive = "open" + width = 0 + height = 720 + fill_type = "stretch" + vcrf = 1 + gop = 250 + preserve_hdr_switch = "OFF" + codec_tag = "hvc1" + + } + audio_template { + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 44100 + audio_channel = 2 + + } + segment_type = "ts" } resource "tencentcloud_vod_procedure_template" "foo" { - name = "tf-procedure" + name = "tf-procedure0" comment = "test" sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) media_process_task { adaptive_dynamic_streaming_task_list { - definition = tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id)[1]) } snapshot_by_time_offset_task_list { - definition = tencentcloud_vod_snapshot_by_time_offset_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_snapshot_by_time_offset_template.foo.id)[1]) ext_time_offset_list = [ "3.5s" ] } image_sprite_task_list { - definition = tencentcloud_vod_image_sprite_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_image_sprite_template.foo.id)[1]) + } + transcode_task_list { + definition = tonumber(split("#", tencentcloud_vod_transcode_template.transcode_template.id)[1]) } } } diff --git a/tencentcloud/services/vod/resource_tc_vod_procedure_template_test.go b/tencentcloud/services/vod/resource_tc_vod_procedure_template_test.go index df8385cc41..282b7340bf 100644 --- a/tencentcloud/services/vod/resource_tc_vod_procedure_template_test.go +++ b/tencentcloud/services/vod/resource_tc_vod_procedure_template_test.go @@ -48,14 +48,12 @@ func init() { func TestAccTencentCloudVodProcedureTemplateResource(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ - PreCheck: func() { tcacctest.AccPreCheck(t) }, - Providers: tcacctest.AccProviders, - CheckDestroy: testAccCheckVodProcedureTemplateDestroy, + PreCheck: func() { tcacctest.AccPreCheck(t) }, + Providers: tcacctest.AccProviders, Steps: []resource.TestStep{ { Config: testAccVodProcedureTemplate, Check: resource.ComposeTestCheckFunc( - testAccCheckVodProcedureTemplateExists("tencentcloud_vod_procedure_template.foo"), resource.TestCheckResourceAttr("tencentcloud_vod_procedure_template.foo", "name", "tf-procedure0"), resource.TestCheckResourceAttr("tencentcloud_vod_procedure_template.foo", "comment", "test"), resource.TestCheckResourceAttr("tencentcloud_vod_procedure_template.foo", "media_process_task.#", "1"), @@ -67,6 +65,7 @@ func TestAccTencentCloudVodProcedureTemplateResource(t *testing.T) { resource.TestCheckResourceAttrSet("tencentcloud_vod_procedure_template.foo", "media_process_task.0.adaptive_dynamic_streaming_task_list.0.definition"), resource.TestCheckResourceAttrSet("tencentcloud_vod_procedure_template.foo", "media_process_task.0.snapshot_by_time_offset_task_list.0.definition"), resource.TestCheckResourceAttrSet("tencentcloud_vod_procedure_template.foo", "media_process_task.0.image_sprite_task_list.0.definition"), + resource.TestCheckResourceAttrSet("tencentcloud_vod_procedure_template.foo", "media_process_task.0.transcode_task_list.0.definition"), resource.TestCheckResourceAttrSet("tencentcloud_vod_procedure_template.foo", "create_time"), resource.TestCheckResourceAttrSet("tencentcloud_vod_procedure_template.foo", "update_time"), ), @@ -160,56 +159,254 @@ func testAccCheckVodProcedureTemplateExists(n string) resource.TestCheckFunc { } } -const testAccVodProcedureTemplate = testAccVodAdaptiveDynamicStreamingTemplate + testAccVodSnapshotByTimeOffsetTemplate + testAccVodImageSpriteTemplate + ` +const testAccVodProcedureTemplate = ` resource "tencentcloud_vod_sub_application" "sub_application" { - name = "subapplication" + name = "procedure-subapplication" status = "On" description = "this is sub application" } +resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { + format = "HLS" + name = "tf-adaptive" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + drm_type = "SimpleAES" + disable_higher_video_bitrate = false + disable_higher_video_resolution = false + comment = "test" + + stream_info { + video { + codec = "libx264" + fps = 3 + bitrate = 128 + } + audio { + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 32000 + } + remove_audio = true + } + stream_info { + video { + codec = "libx264" + fps = 4 + bitrate = 256 + } + audio { + codec = "libfdk_aac" + bitrate = 256 + sample_rate = 44100 + } + remove_audio = true + tehd_config { + type = "TEHD-100" + } + } +} + +resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { + name = "tf-snapshot" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + width = 128 + height = 128 + resolution_adaptive = false + format = "png" + comment = "test" + fill_type = "white" +} + +resource "tencentcloud_vod_image_sprite_template" "foo" { + sample_type = "Percent" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + sample_interval = 10 + row_count = 3 + column_count = 3 + name = "tf-sprite" + comment = "test" + fill_type = "stretch" + width = 128 + height = 128 + resolution_adaptive = false +} + +resource "tencentcloud_vod_transcode_template" "transcode_template" { + container = "mp4" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + name = "720pTranscodeTemplate" + comment = "test transcode mp4 720p update" + remove_video = 0 + remove_audio = 0 + video_template { + codec = "libx264" + fps = 26 + bitrate = 1000 + resolution_adaptive = "open" + width = 0 + height = 720 + fill_type = "stretch" + vcrf = 1 + gop = 250 + preserve_hdr_switch = "OFF" + codec_tag = "hvc1" + + } + audio_template { + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 44100 + audio_channel = 2 + + } + segment_type = "ts" +} + resource "tencentcloud_vod_procedure_template" "foo" { name = "tf-procedure0" comment = "test" sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) media_process_task { adaptive_dynamic_streaming_task_list { - definition = tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id)[1]) } snapshot_by_time_offset_task_list { - definition = tencentcloud_vod_snapshot_by_time_offset_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_snapshot_by_time_offset_template.foo.id)[1]) ext_time_offset_list = [ "3.5s" ] } image_sprite_task_list { - definition = tencentcloud_vod_image_sprite_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_image_sprite_template.foo.id)[1]) + } + transcode_task_list { + definition = tonumber(split("#", tencentcloud_vod_transcode_template.transcode_template.id)[1]) } } } ` -const testAccVodProcedureTemplateUpdate = testAccVodAdaptiveDynamicStreamingTemplate + testAccVodSnapshotByTimeOffsetTemplate + testAccVodImageSpriteTemplate + ` +const testAccVodProcedureTemplateUpdate = ` resource "tencentcloud_vod_sub_application" "sub_application" { - name = "subapplication" + name = "procedure-subapplication" status = "On" description = "this is sub application" } +resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { + format = "HLS" + name = "tf-adaptive" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + drm_type = "SimpleAES" + disable_higher_video_bitrate = false + disable_higher_video_resolution = false + comment = "test" + + stream_info { + video { + codec = "libx264" + fps = 3 + bitrate = 128 + } + audio { + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 32000 + } + remove_audio = true + } + stream_info { + video { + codec = "libx264" + fps = 4 + bitrate = 256 + } + audio { + codec = "libfdk_aac" + bitrate = 256 + sample_rate = 44100 + } + remove_audio = true + tehd_config { + type = "TEHD-100" + } + } +} + +resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { + name = "tf-snapshot" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + width = 128 + height = 128 + resolution_adaptive = false + format = "png" + comment = "test" + fill_type = "white" +} + +resource "tencentcloud_vod_image_sprite_template" "foo" { + sample_type = "Percent" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + sample_interval = 10 + row_count = 3 + column_count = 3 + name = "tf-sprite" + comment = "test" + fill_type = "stretch" + width = 128 + height = 128 + resolution_adaptive = false +} + +resource "tencentcloud_vod_transcode_template" "transcode_template" { + container = "mp4" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + name = "720pTranscodeTemplate" + comment = "test transcode mp4 720p update" + remove_video = 0 + remove_audio = 0 + video_template { + codec = "libx264" + fps = 26 + bitrate = 1000 + resolution_adaptive = "open" + width = 0 + height = 720 + fill_type = "stretch" + vcrf = 1 + gop = 250 + preserve_hdr_switch = "OFF" + codec_tag = "hvc1" + + } + audio_template { + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 44100 + audio_channel = 2 + + } + segment_type = "ts" +} + resource "tencentcloud_vod_procedure_template" "foo" { name = "tf-procedure0" comment = "test-update" sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) media_process_task { adaptive_dynamic_streaming_task_list { - definition = tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id)[1]) } snapshot_by_time_offset_task_list { - definition = tencentcloud_vod_snapshot_by_time_offset_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_snapshot_by_time_offset_template.foo.id)[1]) ext_time_offset_list = [ "3.5s", "4.0s" ] } + transcode_task_list { + definition = tonumber(split("#", tencentcloud_vod_transcode_template.transcode_template.id)[1]) + } } } ` diff --git a/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.go b/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.go index 37ba5cae40..4b86cead3f 100644 --- a/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.go +++ b/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.go @@ -178,13 +178,18 @@ func resourceTencentCloudVodSampleSnapshotTemplateRead(d *schema.ResourceData, m service := VodService{client: meta.(tccommon.ProviderMeta).GetAPIV3Conn()} + var ( + subAppId int + definition string + ) idSplit := strings.Split(d.Id(), tccommon.FILED_SP) - if len(idSplit) != 2 { - return fmt.Errorf("sample snapshot id is borken, id is %s", d.Id()) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + } else { + definition = d.Id() } - subAppId := idSplit[0] - definition := idSplit[1] - sampleSnapshotTemplate, err := service.DescribeVodSampleSnapshotTemplateById(ctx, helper.StrToUInt64(subAppId), helper.StrToUInt64(definition)) + sampleSnapshotTemplate, err := service.DescribeVodSampleSnapshotTemplateById(ctx, uint64(subAppId), helper.StrToUInt64(definition)) if err != nil { return err } @@ -195,7 +200,9 @@ func resourceTencentCloudVodSampleSnapshotTemplateRead(d *schema.ResourceData, m return nil } - _ = d.Set("sub_app_id", helper.StrToInt(subAppId)) + if subAppId != 0 { + _ = d.Set("sub_app_id", subAppId) + } if sampleSnapshotTemplate.SampleType != nil { _ = d.Set("sample_type", sampleSnapshotTemplate.SampleType) } @@ -294,7 +301,13 @@ func resourceTencentCloudVodSampleSnapshotTemplateUpdate(d *schema.ResourceData, err := resource.Retry(tccommon.WriteRetryTimeout, func() *resource.RetryError { result, e := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVodClient().ModifySampleSnapshotTemplate(request) if e != nil { - return tccommon.RetryError(e) + if sdkError, ok := e.(*sdkErrors.TencentCloudSDKError); ok { + if sdkError.Code == "FailedOperation" && sdkError.Message == "invalid vod user" { + return resource.RetryableError(e) + } + } + log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), e.Error()) + return resource.NonRetryableError(e) } else { log.Printf("[DEBUG]%s api[%s] success, request body [%s], response body [%s]\n", logId, request.GetAction(), request.ToJsonString(), result.ToJsonString()) } diff --git a/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.md b/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.md index 5cbe6d0485..661ef74d64 100644 --- a/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.md +++ b/tencentcloud/services/vod/resource_tc_vod_sample_snapshot_template.md @@ -25,7 +25,7 @@ resource "tencentcloud_vod_sample_snapshot_template" "sample_snapshot_template" Import -vod snapshot template can be imported using the id, e.g. +vod snapshot template can be imported using the id($subAppId#$templateId), e.g. ``` terraform import tencentcloud_vod_sample_snapshot_template.sample_snapshot_template $subAppId#$templateId diff --git a/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.go b/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.go index 233d984d07..1824bad154 100644 --- a/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.go +++ b/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.go @@ -5,12 +5,14 @@ import ( "fmt" "log" "strconv" + "strings" "time" tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + sdkErrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" vod "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vod/v20180717" "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" @@ -66,7 +68,7 @@ func ResourceTencentCloudVodSnapshotByTimeOffsetTemplate() *schema.Resource { "sub_app_id": { Type: schema.TypeInt, Optional: true, - Description: "Subapplication ID in VOD. If you need to access a resource in a subapplication, enter the subapplication ID in this field; otherwise, leave it empty.", + Description: "The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID.", }, "fill_type": { Type: schema.TypeString, @@ -85,6 +87,13 @@ func ResourceTencentCloudVodSnapshotByTimeOffsetTemplate() *schema.Resource { Computed: true, Description: "Last modified time of template in ISO date format.", }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Template type, value range:\n" + + "- Preset: system preset template;\n" + + "- Custom: user-defined templates.", + }, }, } } @@ -107,8 +116,12 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateCreate(d *schema.Resourc if v, ok := d.GetOk("comment"); ok { request.Comment = helper.String(v.(string)) } + var resourceId string if v, ok := d.GetOk("sub_app_id"); ok { - request.SubAppId = helper.IntUint64(v.(int)) + subAppId := v.(int) + resourceId += helper.IntToStr(subAppId) + resourceId += tccommon.FILED_SP + request.SubAppId = helper.IntUint64(subAppId) } request.FillType = helper.String(d.Get("fill_type").(string)) @@ -118,8 +131,13 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateCreate(d *schema.Resourc ratelimit.Check(request.GetAction()) response, err = meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseVodClient().CreateSnapshotByTimeOffsetTemplate(request) if err != nil { + if sdkError, ok := err.(*sdkErrors.TencentCloudSDKError); ok { + if sdkError.Code == "FailedOperation" && sdkError.Message == "invalid vod user" { + return resource.RetryableError(err) + } + } log.Printf("[CRITAL]%s api[%s] fail, reason:%s", logId, request.GetAction(), err.Error()) - return tccommon.RetryError(err) + return resource.NonRetryableError(err) } return nil }) @@ -129,7 +147,8 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateCreate(d *schema.Resourc if response == nil || response.Response == nil { return fmt.Errorf("for vod snapshot by time offset template creation, response is nil") } - d.SetId(strconv.FormatUint(*response.Response.Definition, 10)) + resourceId += strconv.FormatUint(*response.Response.Definition, 10) + d.SetId(resourceId) return resourceTencentCloudVodSnapshotByTimeOffsetTemplateRead(d, meta) } @@ -141,14 +160,21 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateRead(d *schema.ResourceD var ( logId = tccommon.GetLogId(tccommon.ContextNil) ctx = context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id = d.Id() - subAppId = d.Get("sub_app_id").(int) + subAppId int + definition string client = meta.(tccommon.ProviderMeta).GetAPIV3Conn() vodService = VodService{client: client} ) + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + } else { + definition = d.Id() + } // waiting for refreshing cache time.Sleep(30 * time.Second) - template, has, err := vodService.DescribeSnapshotByTimeOffsetTemplatesById(ctx, id, subAppId) + template, has, err := vodService.DescribeSnapshotByTimeOffsetTemplatesById(ctx, definition, subAppId) if err != nil { return err } @@ -158,6 +184,7 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateRead(d *schema.ResourceD } _ = d.Set("name", template.Name) + _ = d.Set("type", template.Type) _ = d.Set("width", template.Width) _ = d.Set("height", template.Height) _ = d.Set("resolution_adaptive", *template.ResolutionAdaptive == "open") @@ -166,6 +193,9 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateRead(d *schema.ResourceD _ = d.Set("fill_type", template.FillType) _ = d.Set("create_time", template.CreateTime) _ = d.Set("update_time", template.UpdateTime) + if subAppId != 0 { + _ = d.Set("sub_app_id", subAppId) + } return nil } @@ -176,12 +206,33 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateUpdate(d *schema.Resourc var ( logId = tccommon.GetLogId(tccommon.ContextNil) request = vod.NewModifySnapshotByTimeOffsetTemplateRequest() - id = d.Id() + subAppId int + definition string changeFlag = false ) - idUint, _ := strconv.ParseUint(id, 0, 64) - request.Definition = &idUint + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + request.SubAppId = helper.IntUint64(subAppId) + } else { + definition = d.Id() + if v, ok := d.GetOk("sub_app_id"); ok { + request.SubAppId = helper.IntUint64(v.(int)) + } + } + + request.Definition = helper.StrToUint64Point(definition) + + immutableArgs := []string{"sub_app_id"} + + for _, v := range immutableArgs { + if d.HasChange(v) { + return fmt.Errorf("argument `%s` cannot be changed", v) + } + } + if d.HasChange("name") { changeFlag = true request.Name = helper.String(d.Get("name").(string)) @@ -200,10 +251,6 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateUpdate(d *schema.Resourc changeFlag = true request.Comment = helper.String(d.Get("comment").(string)) } - if d.HasChange("sub_app_id") { - changeFlag = true - request.SubAppId = helper.IntUint64(d.Get("sub_app_id").(int)) - } if d.HasChange("fill_type") { changeFlag = true request.FillType = helper.String(d.Get("fill_type").(string)) @@ -236,12 +283,25 @@ func resourceTencentCloudVodSnapshotByTimeOffsetTemplateDelete(d *schema.Resourc logId := tccommon.GetLogId(tccommon.ContextNil) ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) - id := d.Id() + var ( + subAppId int + definition string + ) + idSplit := strings.Split(d.Id(), tccommon.FILED_SP) + if len(idSplit) == 2 { + subAppId = helper.StrToInt(idSplit[0]) + definition = idSplit[1] + } else { + definition = d.Id() + if v, ok := d.GetOk("sub_app_id"); ok { + subAppId = v.(int) + } + } vodService := VodService{ client: meta.(tccommon.ProviderMeta).GetAPIV3Conn(), } - if err := vodService.DeleteSnapshotByTimeOffsetTemplate(ctx, id, uint64(d.Get("sub_app_id").(int))); err != nil { + if err := vodService.DeleteSnapshotByTimeOffsetTemplate(ctx, definition, uint64(subAppId)); err != nil { return err } diff --git a/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.md b/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.md index 8b6dc8d6f5..aac4300751 100644 --- a/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.md +++ b/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template.md @@ -16,8 +16,8 @@ resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { Import -VOD snapshot by time offset template can be imported using the id, e.g. +VOD snapshot by time offset template can be imported using the id($subAppId#$templateId), e.g. ``` -$ terraform import tencentcloud_vod_snapshot_by_time_offset_template.foo 46906 +$ terraform import tencentcloud_vod_snapshot_by_time_offset_template.foo $subAppId#$templateId ``` \ No newline at end of file diff --git a/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template_test.go b/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template_test.go index 9fda33d5b2..e70bce0f54 100644 --- a/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template_test.go +++ b/tencentcloud/services/vod/resource_tc_vod_snapshot_by_time_offset_template_test.go @@ -4,10 +4,12 @@ import ( "context" "fmt" "strconv" + "strings" "testing" tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" svcvod "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/services/vod" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -74,6 +76,7 @@ func TestAccTencentCloudVodSnapshotByTimeOffsetTemplateResource(t *testing.T) { resource.TestCheckResourceAttr("tencentcloud_vod_snapshot_by_time_offset_template.foo", "fill_type", "white"), resource.TestCheckResourceAttrSet("tencentcloud_vod_snapshot_by_time_offset_template.foo", "create_time"), resource.TestCheckResourceAttrSet("tencentcloud_vod_snapshot_by_time_offset_template.foo", "update_time"), + resource.TestCheckResourceAttrSet("tencentcloud_vod_snapshot_by_time_offset_template.foo", "type"), ), }, { @@ -89,10 +92,9 @@ func TestAccTencentCloudVodSnapshotByTimeOffsetTemplateResource(t *testing.T) { ), }, { - ResourceName: "tencentcloud_vod_snapshot_by_time_offset_template.foo", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"sub_app_id"}, + ResourceName: "tencentcloud_vod_snapshot_by_time_offset_template.foo", + ImportState: true, + ImportStateVerify: true, }, }, }) @@ -107,11 +109,13 @@ func testAccCheckVodSnapshotByTimeOffsetTemplateDestroy(s *terraform.State) erro if rs.Type != "tencentcloud_vod_snapshot_by_time_offset_template" { continue } - var ( - filter = map[string]interface{}{ - "definitions": []string{rs.Primary.ID}, - } - ) + idSplit := strings.Split(rs.Primary.ID, tccommon.FILED_SP) + subAppId := helper.StrToInt(idSplit[0]) + definition := idSplit[1] + filter := map[string]interface{}{ + "definitions": []string{definition}, + "sub_appid": subAppId, + } templates, err := vodService.DescribeSnapshotByTimeOffsetTemplatesByFilter(ctx, filter) if err != nil { @@ -139,11 +143,13 @@ func testAccCheckVodSnapshotByTimeOffsetTemplateExists(n string) resource.TestCh } vodService := svcvod.NewVodService(tcacctest.AccProvider.Meta().(tccommon.ProviderMeta).GetAPIV3Conn()) - var ( - filter = map[string]interface{}{ - "definitions": []string{rs.Primary.ID}, - } - ) + idSplit := strings.Split(rs.Primary.ID, tccommon.FILED_SP) + subAppId := helper.StrToInt(idSplit[0]) + definition := idSplit[1] + filter := map[string]interface{}{ + "definitions": []string{definition}, + "sub_appid": subAppId, + } templates, err := vodService.DescribeSnapshotByTimeOffsetTemplatesByFilter(ctx, filter) if err != nil { return err @@ -156,8 +162,15 @@ func testAccCheckVodSnapshotByTimeOffsetTemplateExists(n string) resource.TestCh } const testAccVodSnapshotByTimeOffsetTemplate = ` +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "sbtot-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { name = "tf-snapshot" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) width = 128 height = 128 resolution_adaptive = false @@ -168,8 +181,15 @@ resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { ` const testAccVodSnapshotByTimeOffsetTemplateUpdate = ` +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "sbtot-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { name = "tf-snapshot-update" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) width = 129 height = 129 resolution_adaptive = true diff --git a/tencentcloud/services/vod/service_tencentcloud_vod.go b/tencentcloud/services/vod/service_tencentcloud_vod.go index 2a1ad15ceb..781176db4d 100644 --- a/tencentcloud/services/vod/service_tencentcloud_vod.go +++ b/tencentcloud/services/vod/service_tencentcloud_vod.go @@ -75,10 +75,13 @@ func (me *VodService) DescribeAdaptiveDynamicStreamingTemplatesById(ctx context. var ( filter = map[string]interface{}{ "definitions": []string{templateId}, - "sub_appid": subAppId, } ) + if subAppId != 0 { + filter["sub_appid"] = subAppId + } + templates, errRet := me.DescribeAdaptiveDynamicStreamingTemplatesByFilter(ctx, filter) if errRet != nil { return @@ -369,10 +372,12 @@ func (me *VodService) DescribeImageSpriteTemplatesById(ctx context.Context, temp var ( filter = map[string]interface{}{ "definitions": []string{templateId}, - "sub_appid": subAppId, } ) + if subAppId != 0 { + filter["sub_appid"] = subAppId + } templates, errRet := me.DescribeImageSpriteTemplatesByFilter(ctx, filter) if errRet != nil { return @@ -515,7 +520,9 @@ func (me *VodService) DescribeVodSampleSnapshotTemplateById(ctx context.Context, logId := tccommon.GetLogId(ctx) request := vod.NewDescribeSampleSnapshotTemplatesRequest() - request.SubAppId = helper.Uint64(subAppId) + if subAppId != 0 { + request.SubAppId = helper.Uint64(subAppId) + } request.Definitions = []*uint64{helper.Uint64(definition)} defer func() { diff --git a/website/docs/r/vod_adaptive_dynamic_streaming_template.html.markdown b/website/docs/r/vod_adaptive_dynamic_streaming_template.html.markdown index 55fefeba0e..01e00af27e 100644 --- a/website/docs/r/vod_adaptive_dynamic_streaming_template.html.markdown +++ b/website/docs/r/vod_adaptive_dynamic_streaming_template.html.markdown @@ -14,44 +14,36 @@ Provide a resource to create a VOD adaptive dynamic streaming template. ## Example Usage ```hcl +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "adaptive-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { format = "HLS" name = "tf-adaptive" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) drm_type = "SimpleAES" disable_higher_video_bitrate = false disable_higher_video_resolution = false comment = "test" - stream_info { - video { - codec = "libx265" - fps = 4 - bitrate = 129 - resolution_adaptive = false - width = 128 - height = 128 - fill_type = "stretch" - } - audio { - codec = "libmp3lame" - bitrate = 129 - sample_rate = 44100 - audio_channel = "dual" - } - remove_audio = false - } stream_info { video { codec = "libx264" - fps = 4 - bitrate = 256 + fps = 3 + bitrate = 128 } audio { codec = "libfdk_aac" - bitrate = 256 - sample_rate = 44100 + bitrate = 128 + sample_rate = 32000 } remove_audio = true + tehd_config { + type = "TEHD-100" + } } } ``` @@ -67,7 +59,7 @@ The following arguments are supported: * `disable_higher_video_bitrate` - (Optional, Bool) Whether to prohibit transcoding video from low bitrate to high bitrate. Valid values: `false`,`true`. `false`: no, `true`: yes. Default value: `false`. * `disable_higher_video_resolution` - (Optional, Bool) Whether to prohibit transcoding from low resolution to high resolution. Valid values: `false`,`true`. `false`: no, `true`: yes. Default value: `false`. * `drm_type` - (Optional, String, ForceNew) DRM scheme type. Valid values: `SimpleAES`. If this field is an empty string, DRM will not be performed on the video. -* `sub_app_id` - (Optional, Int) Subapplication ID in VOD. If you need to access a resource in a subapplication, enter the subapplication ID in this field; otherwise, leave it empty. +* `sub_app_id` - (Optional, Int) The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID. The `audio` object of `stream_info` supports the following: @@ -81,15 +73,38 @@ The `stream_info` object supports the following: * `audio` - (Required, List) Audio parameter information. * `video` - (Required, List) Video parameter information. * `remove_audio` - (Optional, Bool) Whether to remove audio stream. Valid values: `false`: no, `true`: yes. `false` by default. +* `remove_video` - (Optional, Bool) Whether to remove video stream. Valid values: `false`: no, `true`: yes. `false` by default. +* `tehd_config` - (Optional, List) Extremely fast HD transcoding parameters. + +The `tehd_config` object of `stream_info` supports the following: + +* `type` - (Required, String) Extreme high-speed HD type, available values: +- TEHD-100: super high definition-100th; +- OFF: turn off Ultra High definition. +* `max_video_bitrate` - (Optional, Int) Video bitrate limit, which is valid when Type specifies extreme speed HD type. If you leave it empty or enter 0, there is no video bitrate limit. The `video` object of `stream_info` supports the following: * `bitrate` - (Required, Int) Bitrate of video stream in Kbps. Value range: `0` and `[128, 35000]`. If the value is `0`, the bitrate of the video will be the same as that of the source video. * `codec` - (Required, String) Video stream encoder. Valid values: `libx264`,`libx265`,`av1`. `libx264`: H.264, `libx265`: H.265, `av1`: AOMedia Video 1. Currently, a resolution within 640x480 must be specified for `H.265`. and the `av1` container only supports mp4. * `fps` - (Required, Int) Video frame rate in Hz. Value range: `[0, 60]`. If the value is `0`, the frame rate will be the same as that of the source video. +* `codec_tag` - (Optional, String) Encoding label, valid only if the encoding format of the video stream is H.265 encoding. Available values: +- hvc1: stands for hvc1 tag; +- hev1: stands for the hev1 tag; +Default value: hvc1. * `fill_type` - (Optional, String) Fill type. Fill refers to the way of processing a screenshot when its aspect ratio is different from that of the source video. The following fill types are supported: `stretch`: stretch. The screenshot will be stretched frame by frame to match the aspect ratio of the source video, which may make the screenshot shorter or longer; `black`: fill with black. This option retains the aspect ratio of the source video for the screenshot and fills the unmatched area with black color blocks. Default value: black. Note: this field may return null, indicating that no valid values can be obtained. +* `gop` - (Optional, Int) Interval between Keyframe I frames, value range: 0 and [1, 100000], unit: number of frames. When you fill in 0 or leave it empty, the gop length is automatically set. * `height` - (Optional, Int) Maximum value of the height (or short side) of a video stream in px. Value range: `0` and `[128, 4096]`. If both `width` and `height` are `0`, the resolution will be the same as that of the source video; If `width` is `0`, but `height` is not `0`, `width` will be proportionally scaled; If `width` is not `0`, but `height` is `0`, `height` will be proportionally scaled; If both `width` and `height` are not `0`, the custom resolution will be used. Default value: `0`. Note: this field may return null, indicating that no valid values can be obtained. +* `preserve_hdr_switch` - (Optional, String) Whether the transcoding output still maintains HDR when the original video is HDR (High Dynamic Range). Value range: +- ON: if the original file is HDR, the transcoding output remains HDR;, otherwise the transcoding output is SDR (Standard Dynamic Range); +- OFF: regardless of whether the original file is HDR or SDR, the transcoding output is SDR; +Default value: OFF. * `resolution_adaptive` - (Optional, Bool) Resolution adaption. Valid values: `true`,`false`. `true`: enabled. In this case, `width` represents the long side of a video, while `height` the short side; `false`: disabled. In this case, `width` represents the width of a video, while `height` the height. Default value: `true`. Note: this field may return null, indicating that no valid values can be obtained. +* `vcrf` - (Optional, Int) Video constant bit rate control factor, value range is [1,51]. +Note: +- If this parameter is specified, the bitrate control method of CRF will be used for transcoding (the video bitrate will no longer take effect); +- This field is required when the video stream encoding format is H.266. The recommended value is 28; +- If there are no special requirements, it is not recommended to specify this parameter. * `width` - (Optional, Int) Maximum value of the width (or long side) of a video stream in px. Value range: `0` and `[128, 4096]`. If both `width` and `height` are `0`, the resolution will be the same as that of the source video; If `width` is `0`, but `height` is not `0`, `width` will be proportionally scaled; If `width` is not `0`, but `height` is `0`, `height` will be proportionally scaled; If both `width` and `height` are not `0`, the custom resolution will be used. Default value: `0`. Note: this field may return null, indicating that no valid values can be obtained. ## Attributes Reference @@ -103,9 +118,9 @@ In addition to all arguments above, the following attributes are exported: ## Import -VOD adaptive dynamic streaming template can be imported using the id, e.g. +VOD adaptive dynamic streaming template can be imported using the id($subAppId#$templateId), e.g. ``` -$ terraform import tencentcloud_vod_adaptive_dynamic_streaming_template.foo 169141 +$ terraform import tencentcloud_vod_adaptive_dynamic_streaming_template.foo $subAppId#$templateId ``` diff --git a/website/docs/r/vod_image_sprite_template.html.markdown b/website/docs/r/vod_image_sprite_template.html.markdown index 9c4244100b..345783bd05 100644 --- a/website/docs/r/vod_image_sprite_template.html.markdown +++ b/website/docs/r/vod_image_sprite_template.html.markdown @@ -14,8 +14,15 @@ Provide a resource to create a VOD image sprite template. ## Example Usage ```hcl +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "image-sprite-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_image_sprite_template" "foo" { sample_type = "Percent" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) sample_interval = 10 row_count = 3 column_count = 3 @@ -39,9 +46,14 @@ The following arguments are supported: * `sample_type` - (Required, String) Sampling type. Valid values: `Percent`, `Time`. `Percent`: by percent. `Time`: by time interval. * `comment` - (Optional, String) Template description. Length limit: 256 characters. * `fill_type` - (Optional, String) Fill refers to the way of processing a screenshot when its aspect ratio is different from that of the source video. The following fill types are supported: `stretch`: stretch. The screenshot will be stretched frame by frame to match the aspect ratio of the source video, which may make the screenshot shorter or longer; `black`: fill with black. This option retains the aspect ratio of the source video for the screenshot and fills the unmatched area with black color blocks. Default value: `black`. +* `format` - (Optional, String) Image format, Valid values: +- jpg: jpg format; +- png: png format; +- webp: webp format; +Default value: jpg. * `height` - (Optional, Int) Maximum value of the `height` (or short side) of a screenshot in px. Value range: 0 and [128, 4,096]. If both `width` and `height` are `0`, the resolution will be the same as that of the source video; If `width` is `0`, but `height` is not `0`, `width` will be proportionally scaled; If `width` is not `0`, but `height` is `0`, `height` will be proportionally scaled; If both `width` and `height` are not `0`, the custom resolution will be used. Default value: `0`. * `resolution_adaptive` - (Optional, Bool) Resolution adaption. Valid values: `true`,`false`. `true`: enabled. In this case, `width` represents the long side of a video, while `height` the short side; `false`: disabled. In this case, `width` represents the width of a video, while `height` the height. Default value: `true`. -* `sub_app_id` - (Optional, Int) Subapplication ID in VOD. If you need to access a resource in a subapplication, enter the subapplication ID in this field; otherwise, leave it empty. +* `sub_app_id` - (Optional, Int) The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID. * `width` - (Optional, Int) Maximum value of the `width` (or long side) of a screenshot in px. Value range: 0 and [128, 4,096]. If both `width` and `height` are `0`, the resolution will be the same as that of the source video; If `width` is `0`, but `height` is not `0`, width will be proportionally scaled; If `width` is not `0`, but `height` is `0`, `height` will be proportionally scaled; If both `width` and `height` are not `0`, the custom resolution will be used. Default value: `0`. ## Attributes Reference @@ -50,14 +62,17 @@ In addition to all arguments above, the following attributes are exported: * `id` - ID of the resource. * `create_time` - Creation time of template in ISO date format. +* `type` - Template type, value range: +- Preset: system preset template; +- Custom: user-defined templates. * `update_time` - Last modified time of template in ISO date format. ## Import -VOD image sprite template can be imported using the id, e.g. +VOD image sprite template can be imported using the id($subAppId#$templateId), e.g. ``` -$ terraform import tencentcloud_vod_image_sprite_template.foo 51156 +$ terraform import tencentcloud_vod_image_sprite_template.foo $subAppId#$templateId ``` diff --git a/website/docs/r/vod_procedure_template.html.markdown b/website/docs/r/vod_procedure_template.html.markdown index e5d885f57f..659db1466a 100644 --- a/website/docs/r/vod_procedure_template.html.markdown +++ b/website/docs/r/vod_procedure_template.html.markdown @@ -14,9 +14,16 @@ Provide a resource to create a VOD procedure template. ## Example Usage ```hcl +resource "tencentcloud_vod_sub_application" "sub_application" { + name = "procedure-subapplication" + status = "On" + description = "this is sub application" +} + resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { format = "HLS" name = "tf-adaptive" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) drm_type = "SimpleAES" disable_higher_video_bitrate = false disable_higher_video_resolution = false @@ -24,21 +31,16 @@ resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { stream_info { video { - codec = "libx265" - fps = 4 - bitrate = 129 - resolution_adaptive = false - width = 128 - height = 128 - fill_type = "stretch" + codec = "libx264" + fps = 3 + bitrate = 128 } audio { - codec = "libmp3lame" - bitrate = 129 - sample_rate = 44100 - audio_channel = "dual" + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 32000 } - remove_audio = false + remove_audio = true } stream_info { video { @@ -52,12 +54,16 @@ resource "tencentcloud_vod_adaptive_dynamic_streaming_template" "foo" { sample_rate = 44100 } remove_audio = true + tehd_config { + type = "TEHD-100" + } } } resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { name = "tf-snapshot" - width = 130 + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + width = 128 height = 128 resolution_adaptive = false format = "png" @@ -67,6 +73,7 @@ resource "tencentcloud_vod_snapshot_by_time_offset_template" "foo" { resource "tencentcloud_vod_image_sprite_template" "foo" { sample_type = "Percent" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) sample_interval = 10 row_count = 3 column_count = 3 @@ -78,28 +85,56 @@ resource "tencentcloud_vod_image_sprite_template" "foo" { resolution_adaptive = false } -resource "tencentcloud_vod_sub_application" "sub_application" { - name = "subapplication" - status = "On" - description = "this is sub application" +resource "tencentcloud_vod_transcode_template" "transcode_template" { + container = "mp4" + sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) + name = "720pTranscodeTemplate" + comment = "test transcode mp4 720p update" + remove_video = 0 + remove_audio = 0 + video_template { + codec = "libx264" + fps = 26 + bitrate = 1000 + resolution_adaptive = "open" + width = 0 + height = 720 + fill_type = "stretch" + vcrf = 1 + gop = 250 + preserve_hdr_switch = "OFF" + codec_tag = "hvc1" + + } + audio_template { + codec = "libfdk_aac" + bitrate = 128 + sample_rate = 44100 + audio_channel = 2 + + } + segment_type = "ts" } resource "tencentcloud_vod_procedure_template" "foo" { - name = "tf-procedure" + name = "tf-procedure0" comment = "test" sub_app_id = tonumber(split("#", tencentcloud_vod_sub_application.sub_application.id)[1]) media_process_task { adaptive_dynamic_streaming_task_list { - definition = tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_adaptive_dynamic_streaming_template.foo.id)[1]) } snapshot_by_time_offset_task_list { - definition = tencentcloud_vod_snapshot_by_time_offset_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_snapshot_by_time_offset_template.foo.id)[1]) ext_time_offset_list = [ "3.5s" ] } image_sprite_task_list { - definition = tencentcloud_vod_image_sprite_template.foo.id + definition = tonumber(split("#", tencentcloud_vod_image_sprite_template.foo.id)[1]) + } + transcode_task_list { + definition = tonumber(split("#", tencentcloud_vod_transcode_template.transcode_template.id)[1]) } } } @@ -110,21 +145,36 @@ resource "tencentcloud_vod_procedure_template" "foo" { The following arguments are supported: * `name` - (Required, String, ForceNew) Task flow name (up to 20 characters). +* `ai_analysis_task` - (Optional, List) Parameter of AI-based content analysis task. +* `ai_recognition_task` - (Optional, List) Type parameter of AI-based content recognition task. * `comment` - (Optional, String) Template description. Length limit: 256 characters. * `media_process_task` - (Optional, List) Parameter of video processing task. -* `sub_app_id` - (Optional, Int) Subapplication ID in VOD. For customers who activate VOD from December 25, 2023, if they access the resources in the VOD application (whether it is the default application or the newly created application), you must fill in this field as Application ID. +* `review_audio_video_task` - (Optional, List) Type parameter of AI-based content recognition task. +* `sub_app_id` - (Optional, Int) The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID. The `adaptive_dynamic_streaming_task_list` object of `media_process_task` supports the following: * `definition` - (Required, String) Adaptive bitrate streaming template ID. * `watermark_list` - (Optional, List) List of up to `10` image or text watermarks. Note: this field may return null, indicating that no valid values can be obtained. +The `ai_analysis_task` object supports the following: + +* `definition` - (Optional, String) Video content analysis template ID. + +The `ai_recognition_task` object supports the following: + +* `definition` - (Optional, String) Intelligent video recognition template ID. + The `animated_graphic_task_list` object of `media_process_task` supports the following: * `definition` - (Required, String) Animated image generating template ID. * `end_time_offset` - (Required, Float64) End time of animated image in video in seconds. * `start_time_offset` - (Required, Float64) Start time of animated image in video in seconds. +The `copy_right_watermark` object of `transcode_task_list` supports the following: + +* `text` - (Optional, String) Copyright information, maximum length is 200 characters. + The `cover_by_snapshot_task_list` object of `media_process_task` supports the following: * `definition` - (Required, String) Time point screen capturing template ID. @@ -132,6 +182,10 @@ The `cover_by_snapshot_task_list` object of `media_process_task` supports the fo * `position_value` - (Required, Float64) Screenshot position: For time point screen capturing, this means to take a screenshot at a specified time point (in seconds) and use it as the cover. For percentage screen capturing, this value means to take a screenshot at a specified percentage of the video duration and use it as the cover. * `watermark_list` - (Optional, List) List of up to `10` image or text watermarks. Note: this field may return null, indicating that no valid values can be obtained. +The `head_tail_list` object of `transcode_task_list` supports the following: + +* `definition` - (Optional, String) Video opening/closing credits configuration template ID. + The `image_sprite_task_list` object of `media_process_task` supports the following: * `definition` - (Required, String) Image sprite generating template ID. @@ -156,6 +210,12 @@ The `mosaic_list` object of `transcode_task_list` supports the following: * `x_pos` - (Optional, String) The horizontal position of the origin of the blur relative to the origin of coordinates of the video. `%` and `px` formats are supported: If the string ends in `%`, the XPos of the blur will be the specified percentage of the video width; for example, 10% means that XPos is 10% of the video width; If the string ends in `px`, the XPos of the blur will be the specified px; for example, 100px means that XPos is 100 px. Default value: `0px`. * `y_pos` - (Optional, String) Vertical position of the origin of blur relative to the origin of coordinates of video. `%` and `px` formats are supported: If the string ends in `%`, the YPos of the blur will be the specified percentage of the video height; for example, 10% means that YPos is 10% of the video height; If the string ends in `px`, the YPos of the blur will be the specified px; for example, 100px means that YPos is 100 px. Default value: `0px`. +The `review_audio_video_task` object supports the following: + +* `review_contents` - (Optional, List) The type of moderated content. Valid values: +- `Media`: The original audio/video; +- `Cover`: Thumbnails. + The `sample_snapshot_task_list` object of `media_process_task` supports the following: * `definition` - (Required, String) Sampled screen capturing template ID. @@ -165,12 +225,22 @@ The `snapshot_by_time_offset_task_list` object of `media_process_task` supports * `definition` - (Required, String) Time point screen capturing template ID. * `ext_time_offset_list` - (Optional, List) The list of screenshot time points. `s` and `%` formats are supported: When a time point string ends with `s`, its unit is second. For example, `3.5s` means the 3.5th second of the video; When a time point string ends with `%`, it is marked with corresponding percentage of the video duration. For example, `10%` means that the time point is at the 10% of the video entire duration. +* `time_offset_list` - (Optional, List) List of time points for screencapturing in milliseconds. Note: this field may return null, indicating that no valid values can be obtained. * `watermark_list` - (Optional, List) List of up to `10` image or text watermarks. Note: this field may return null, indicating that no valid values can be obtained. +The `trace_watermark` object of `transcode_task_list` supports the following: + +* `switch` - (Optional, String) Whether to use digital watermarks. This parameter is required. Valid values: ON, OFF. + The `transcode_task_list` object of `media_process_task` supports the following: * `definition` - (Required, String) Video transcoding template ID. +* `copy_right_watermark` - (Optional, List) opyright watermark. +* `end_time_offset` - (Optional, Float64) End time offset of blur in seconds. If this parameter is left empty or `0` is entered, the blur will exist till the last video frame; If this value is greater than `0` (e.g., n), the blur will exist till second n; If this value is smaller than `0` (e.g., -n), the blur will exist till second n before the last video frame. +* `head_tail_list` - (Optional, List) List of video opening/closing credits configuration template IDs. You can enter up to 10 IDs. * `mosaic_list` - (Optional, List) List of blurs. Up to 10 ones can be supported. +* `start_time_offset` - (Optional, Float64) Start time offset of blur in seconds. If this parameter is left empty or `0` is entered, the blur will appear upon the first video frame. If this parameter is left empty or `0` is entered, the blur will appear upon the first video frame; If this value is greater than `0` (e.g., n), the blur will appear at second n after the first video frame; If this value is smaller than `0` (e.g., -n), the blur will appear at second n before the last video frame. +* `trace_watermark` - (Optional, List) Digital watermark. * `watermark_list` - (Optional, List) List of up to `10` image or text watermarks. Note: this field may return null, indicating that no valid values can be obtained. The `watermark_list` object of `adaptive_dynamic_streaming_task_list` supports the following: @@ -219,6 +289,9 @@ In addition to all arguments above, the following attributes are exported: * `id` - ID of the resource. * `create_time` - Creation time of template in ISO date format. +* `type` - Template type, value range: +- Preset: system preset template; +- Custom: user-defined templates. * `update_time` - Last modified time of template in ISO date format. diff --git a/website/docs/r/vod_sample_snapshot_template.html.markdown b/website/docs/r/vod_sample_snapshot_template.html.markdown index e4a9b6833c..ed66435aba 100644 --- a/website/docs/r/vod_sample_snapshot_template.html.markdown +++ b/website/docs/r/vod_sample_snapshot_template.html.markdown @@ -59,7 +59,7 @@ In addition to all arguments above, the following attributes are exported: ## Import -vod snapshot template can be imported using the id, e.g. +vod snapshot template can be imported using the id($subAppId#$templateId), e.g. ``` terraform import tencentcloud_vod_sample_snapshot_template.sample_snapshot_template $subAppId#$templateId diff --git a/website/docs/r/vod_snapshot_by_time_offset_template.html.markdown b/website/docs/r/vod_snapshot_by_time_offset_template.html.markdown index 2613d659c0..c18837bc2f 100644 --- a/website/docs/r/vod_snapshot_by_time_offset_template.html.markdown +++ b/website/docs/r/vod_snapshot_by_time_offset_template.html.markdown @@ -35,7 +35,7 @@ The following arguments are supported: * `format` - (Optional, String) Image format. Valid values: `jpg`, `png`. Default value: `jpg`. * `height` - (Optional, Int) Maximum value of the `height` (or short side) of a screenshot in px. Value range: 0 and [128, 4,096]. If both `width` and `height` are `0`, the resolution will be the same as that of the source video; If `width` is `0`, but `height` is not `0`, `width` will be proportionally scaled; If `width` is not `0`, but `height` is `0`, `height` will be proportionally scaled; If both `width` and `height` are not `0`, the custom resolution will be used. Default value: `0`. * `resolution_adaptive` - (Optional, Bool) Resolution adaption. Valid values: `true`,`false`. `true`: enabled. In this case, `width` represents the long side of a video, while `height` the short side; `false`: disabled. In this case, `width` represents the width of a video, while `height` the height. Default value: `true`. -* `sub_app_id` - (Optional, Int) Subapplication ID in VOD. If you need to access a resource in a subapplication, enter the subapplication ID in this field; otherwise, leave it empty. +* `sub_app_id` - (Optional, Int) The VOD [application](https://intl.cloud.tencent.com/document/product/266/14574) ID. For customers who activate VOD service from December 25, 2023, if they want to access resources in a VOD application (whether it's the default application or a newly created one), they must fill in this field with the application ID. * `width` - (Optional, Int) Maximum value of the `width` (or long side) of a screenshot in px. Value range: 0 and [128, 4,096]. If both `width` and `height` are `0`, the resolution will be the same as that of the source video; If `width` is `0`, but `height` is not `0`, width will be proportionally scaled; If `width` is not `0`, but `height` is `0`, `height` will be proportionally scaled; If both `width` and `height` are not `0`, the custom resolution will be used. Default value: `0`. ## Attributes Reference @@ -44,14 +44,17 @@ In addition to all arguments above, the following attributes are exported: * `id` - ID of the resource. * `create_time` - Creation time of template in ISO date format. +* `type` - Template type, value range: +- Preset: system preset template; +- Custom: user-defined templates. * `update_time` - Last modified time of template in ISO date format. ## Import -VOD snapshot by time offset template can be imported using the id, e.g. +VOD snapshot by time offset template can be imported using the id($subAppId#$templateId), e.g. ``` -$ terraform import tencentcloud_vod_snapshot_by_time_offset_template.foo 46906 +$ terraform import tencentcloud_vod_snapshot_by_time_offset_template.foo $subAppId#$templateId ```