C# 使用豆包 AI 模型实现首尾帧模式的视频生成

体验

欲诚其意者,先致其知,致知在格物。人生太多体验,有悲有喜,有好有坏。没有实践就没有发言权,没有亲自尝试就不要轻易否定,适合你的才是最好的。最近在火山引擎火山方舟平台模型广场中看到豆包推出最强视频生成模型 Doubao-Seedance-1.0-pro,于是也想体验一下其魅力如何。模型提供多种生成方式,被其中一项 "首尾帧" 模式所吸引,即提供首图和尾图两张照片,并结合 AI 对话描述生成结果视频。本文则主要讲述如何使用C#调用平台API实现视频生成功能。

调用 API 前需要注册火山引擎帐号并获得 API 开发密钥。

火山引擎注册地址如下:https://console.volcengine.com/auth/login

选择火山方舟 -> API Key 管理 -> 创建 API Key 即可,请注意编辑权限以保证能够调用对应功能的 API 。

构思

如同人与人之间有效的沟通,为 AI 模型提供符合情境的素材,精准、逻辑清晰的对话描述,才能生成符合预期的结果,不过为了测试其 "思考、创意" 能力 ,我提供了两张风马牛不相及的美女图片,简要描述了一下对话,对话内容:"结合图片,请生成类似周杰伦《红颜如霜》的MV,要求生成音乐"。生图照片素材内容如下:

素材图片首帧为有些 "现代风" 的人物座在汽车后排的场景,尾帧是有些 "复古风" 的人物在女生宿舍的场景,看看 AI 模型根据提供的素材会生成什么样的结果视频,期待中还是夹杂着一丝好奇的。

创建视频生成任务

模型 "思考"和生成视频需要一段时间,因此属于异步操作,首先要做的就是向模型申请创建视频生成任务,Doubao_CreateVideo 方法提供了创建视频任务的能力,基本说明如下表:

| 序号 | 参数名 | 类型 | 说明 |
| 1 | say | string | 对话描述内容。如"请为我生成一段视频" |
| 2 | ApiKey | string | 在火山引擎平台申请的API访问令牌 |
| 3 | first_ImageUrlOrBase64 | string | 首帧图片的可访问URL或图片的Base64编码 |
| 4 | last_ImageUrlOrBase64 | string | 尾帧图片的可访问URL或图片的Base64编码 |
| 5 | rs | string | 指定生成视频的分辨率,默认值为720p 枚举值包括:480p,720p,1080p |
| 6 | rt | string | 指定生成视频的宽高比,默认值为16:9 枚举值包括:16:9,4:3,1:1,3:4,9:16,21:9 |
| 7 | dur | int | 指定生成视频的时长,默认值为 5 秒 最长目前可选择为12秒 |
| 8 | fps | int | 指定生成视频的帧率,默认值为 24 (fps), |
| 9 | wm | bool | 指定生成的视频是否包含水印(AI生成字样) |
| 10 | seed | int | 种子整数,用于控制生成内容的随机性。默认值为11 |
| 11 | cf=false | bool | 是否固定摄像头,默认值为 false。 枚举值:true:固定摄像头。平台会在用户提示词中追加固定摄像头,实际效果不保证。false:不固定摄像头。 |

12 model string 使用的模型ID,默认值为官方强烈推荐的 doubao-seedance-1-0-pro-250528。详细 ID 列表请参考官方API文档进行查询。

方法示例代码如下:

cs 复制代码
string            ErrorMessage = "";
string            ResultJson = "";
public void Doubao_CreateVideo(string say,string ApiKey,string first_ImageUrlOrBase64,string last_ImageUrlOrBase64
            ,string rs="720p",string rt="16:9",int dur=5,int fps=24,bool wm=true,int seed=11,bool cf=false
            , string model= "doubao-seedance-1-0-pro-250528")
        {
            string para = string.Format(" --rs {0} --rt {1} --dur {2} --fps {3} --wm {4} --seed {5} --cf {6}",rs,rt,dur,fps,wm,seed,cf);

            string ApiUrl = "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks"; 
            
            WebService ws = new WebService();

            string[] headers = new string[3];
            headers[0] = "Content-Type:application/json";
            headers[1] = "Accept:application/json";
            headers[2] = "Authorization:Bearer " + ApiKey + "";
            StringWriter sw = new StringWriter();
            using (Newtonsoft.Json.JsonWriter writer = new Newtonsoft.Json.JsonTextWriter(sw))
            {
                writer.Formatting = Newtonsoft.Json.Formatting.Indented;
                writer.WriteStartObject();
                writer.WritePropertyName("model");                writer.WriteValue(model);
                writer.WritePropertyName("content");
                writer.WriteStartArray();

                writer.WriteStartObject();
                writer.WritePropertyName("type");                writer.WriteValue("text");
                writer.WritePropertyName("text");                writer.WriteValue(say+para);
                writer.WriteEndObject();

                writer.WriteStartObject();
                writer.WritePropertyName("type"); writer.WriteValue("image_url");
                writer.WritePropertyName("image_url");
                    writer.WriteStartObject();
                    writer.WritePropertyName("url"); writer.WriteValue(first_ImageUrlOrBase64);
                    writer.WriteEndObject();
                writer.WritePropertyName("role"); writer.WriteValue("first_frame");
                writer.WriteEndObject();
                writer.WriteStartObject();
                writer.WritePropertyName("type"); writer.WriteValue("image_url");
                writer.WritePropertyName("image_url");
                writer.WriteStartObject();
                writer.WritePropertyName("url"); writer.WriteValue(last_ImageUrlOrBase64);
                writer.WriteEndObject();
                writer.WritePropertyName("role"); writer.WriteValue("last_frame");
                writer.WriteEndObject();

                writer.WriteEndArray();

                writer.WriteEndObject();
                writer.Flush();
            }
            sw.Close();
            string postData = sw.GetStringBuilder().ToString();
            ErrorMessage = "";
            ResultJson = "";
            string rs2 = ws.GetResponseResult(ApiUrl, Encoding.UTF8, "POST", postData, headers);
            ErrorMessage = ws.ErrorMessage;
            ResultJson = rs2;



        }

其中 WebService 类示例代码如下:

cs 复制代码
    public sealed class WebService
    {
        #region Internal Members

        public string ErrorMessage = "";
        #endregion

        /// <summary>
        /// 构造函数,提供初始化数据的功能,打开Ftp站点
        /// </summary>
        public string GetResponseResult(string url, System.Text.Encoding encoding, string method, string postData)
        {
            return GetResponseResult(url,encoding,method,postData,null);
        }
        private static bool validSecurity(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }
        public string GetResponseResult(string url, System.Text.Encoding encoding, string method, string postData,string[] headers,string ContentType= "application/x-www-form-urlencoded",bool secValid=true)
        {
            method = method.ToUpper();
            if (secValid == false)
            {
                ServicePointManager.ServerCertificateValidationCallback = validSecurity;
            }
            System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12;

            if (method == "GET")
            {
                try
                {
                    WebRequest request2 = WebRequest.Create(@url);

                    request2.Method = method;
                    if (headers != null)
                    {
                        for (int i = 0; i < headers.GetLength(0); i++)
                        {
                            if (headers[i].Split(':').Length < 2)
                            {
                                continue;
                            }

                            if (headers[i].Split(':').Length > 1)
                            {
                                if (headers[i].Split(':')[0] == "Content-Type")
                                {
                                    request2.ContentType = headers[i].Split(':')[1];
                                    continue;
                                }
                            }
                            request2.Headers.Add(headers[i]);
                        }
                    }
                    WebResponse response2 = request2.GetResponse();
                    try
                    {
                        Stream stream = response2.GetResponseStream();
                        StreamReader reader = new StreamReader(stream, encoding);
                        string content2 = reader.ReadToEnd();
                        return content2;
                    }
                    catch (WebException webEx)
                    {
                        if (webEx.Response is HttpWebResponse errorResponse)
                        {
                            string errorBody;
                            using (Stream stream = errorResponse.GetResponseStream())
                            using (StreamReader reader = new StreamReader(stream))
                            {
                                errorBody = reader.ReadToEnd();
                            }
                            return errorBody;
                        }
                        else
                        {
                            Console.WriteLine($"WebException: {webEx.Message}");
                            return webEx.Message;
                        }
                    }

                }
                catch (Exception ex)
                {
                    ErrorMessage = ex.Message;
                    return "";
                }

            }
            if (method == "POST")
            {

                Stream outstream = null;
                Stream instream = null;
                StreamReader sr = null;
                HttpWebResponse response = null;

                HttpWebRequest request = null;
                byte[] data = encoding.GetBytes(postData);
                // 准备请求...
                try
                {
                    // 设置参数
                    request = WebRequest.Create(url) as HttpWebRequest;
                    CookieContainer cookieContainer = new CookieContainer();
                    request.CookieContainer = cookieContainer;
                    request.AllowAutoRedirect = true;
                    request.Method = method;
                    request.Timeout = 1000000;
                    
                    request.ContentType = ContentType;
                    if (headers != null)
                    {
                        for (int i = 0; i < headers.GetLength(0); i++)
                        {
                            if (headers[i].Split(':').Length < 2)
                            {
                                continue;
                            }

                            if (headers[i].Split(':').Length > 1)
                            {
                                if (headers[i].Split(':')[0] == "Host")
                                {
                                    request.Host = headers[i].Split(':')[1];
                                    continue;
                                }
                                else if (headers[i].Split(':')[0] == "Content-Type")
                                {
                                    request.ContentType = headers[i].Split(':')[1];
                                    continue;
                                }
                                else if (headers[i].Split(':')[0] == "Connection")
                                {
                                    request.KeepAlive = headers[i].Split(':')[1] == "close" ? false : true;
                                    continue;
                                }
                                else if (headers[i].Split(':')[0] == "Accept")
                                {
                                    request.Accept = headers[i].Split(':')[1];
                                    continue;
                                }

                            }
                            request.Headers.Add(headers[i]);
                        }
                    }
                    request.ContentLength = data.Length;
                    try
                    {
                        outstream = request.GetRequestStream();
                        outstream.Write(data, 0, data.Length);
                        outstream.Close();
                        //发送请求并获取相应回应数据
                        response = request.GetResponse() as HttpWebResponse;
                        //直到request.GetResponse()程序才开始向目标网页发送Post请求
                        instream = response.GetResponseStream();
                        sr = new StreamReader(instream, encoding);
                        //返回结果网页(html)代码
                        string content = sr.ReadToEnd();
                        sr.Close();
                        sr.Dispose();

                        return content;
                    }
                    catch (WebException webEx)
                    {
                        if (webEx.Response is HttpWebResponse errorResponse)
                        {
                            string errorBody;
                            using (Stream stream = errorResponse.GetResponseStream())
                            using (StreamReader reader = new StreamReader(stream))
                            {
                                errorBody = reader.ReadToEnd();
                            }
                            return errorBody;
                        }
                        else
                        {
                            Console.WriteLine($"WebException: {webEx.Message}");
                            return webEx.Message;
                        }
                    }
                }
                catch (Exception ex)
                {
                    ErrorMessage = ex.Message;
                    return "";
                }
            }
            ErrorMessage = "不正确的方法类型。(目前仅支持GET/POST)";
            return "";

        }//get response result

一些基本说明可参考我的文章:https://blog.csdn.net/michaelline/article/details/139123272?spm=1011.2415.3001.5331

成功调用会返回如下JSON:

XML 复制代码
{"id":"cgt-20251000000008-xxxbk"}

其中的 id 就是创建成功后的任务ID,此时模型正在生成视频...

查询视频生成任务

根据创建视频成功后提供的ID,可以通过查询视频生成任务 API,轮询其生成状态,是否完成。Doubao_QueryVideoTask 方法可产现对任务ID的详情查询,基本说明如下表:

| 序号 | 参数名称 | 参数类型 | 说明 |
| 1 | taskid | string | 要查询的视频生成任务 ID 字符串 |

2 ApiKey string 在火山引擎平台申请的API访问令牌

方法示例代码如下:

cs 复制代码
string  ErrorMessage = "";
string  ResultJson = "";
 public void Doubao_QueryVideoTask(string taskid, string ApiKey)
 {

            string ApiUrl = "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks/" + taskid;
            WebService ws = new WebService();
            string[] headers = new string[2];
            headers[0] = "Content-Type:application/json";
            headers[1] = "Authorization:Bearer " + ApiKey + "";
            ErrorMessage = "";
            ResultJson = "";
            string rs2 = ws.GetResponseResult(ApiUrl, Encoding.UTF8, "GET", "", headers);
            ErrorMessage = ws.ErrorMessage;
            ResultJson = rs2;
}

成功后会返回如下示例:

XML 复制代码
{"id":"cgt-2025108-whpbk","model":"doubao-seedance-1-0-pro-250528",
"status":"succeeded",
"content":
{"video_url":"xxx"},
"usage":{"completion_tokens":103818,"total_tokens":103818},
"created_at":1763455989,"updated_at":1763456064,
"seed":11,
"resolution":"720p",
"ratio":"16:9",
"duration":5,
framespersecond":24}

其中 status 为状态码,succeeded 表示已完成(枚举值包括:queued:排队中、running:任务运行中、cancelled:取消任务,取消状态24h自动删除(只支持排队中状态的任务被取消)、succeeded: 任务成功、failed:任务失败。)。

如果返回JSON中存在 content.video_url 字段的url内容,即可以访问URL或下载播放视频,查看视频生成效果。

查询视频生成任务列表

对于未及时查询单一任务ID的或想查询所有生成中或已完成的视频任务列表,可使用查询视频生成任务列表 API 实现。 该API仅支持查询最近 7 天的历史数据。时间计算统一采用UTC时间戳,返回的7天历史数据范围以用户实际发起批量查询请求的时刻为基准(精确到秒),时间戳区间为 [T-7天, T)。

Doubao_QueryVideoTaskList 方法可产现对任务ID列表的详情查询,基本说明如下表:

| 序号 | 参数名称 | 参数类型 | 说明 |
| 1 | page_num | int | 设置查询列表页的起始页码,默认为1,最大为500 |
| 2 | page_size | int | 设置查询列表页的每页数量,默认为500,最大为500 |
| 3 | filter_status | string | 视频生成状态的过滤条件,默认为 "succeeded"(成功) (枚举值包括:queued:排队中、running:任务运行中、cancelled:取消任务,取消状态24h自动删除(只支持排队中状态的任务被取消)、succeeded: 任务成功、failed:任务失败。) |

4 ApiKey string 在火山引擎平台申请的API访问令牌

方法示例代码如下:

cs 复制代码
string  ErrorMessage = "";
string  ResultJson = "";
public void Doubao_QueryVideoTaskList(int page_num=1,int page_size=500,string filter_status= "succeeded",string ApiKey)
{
           
            string postData = "page_num=" + page_num.ToString() + "&page_size=" + page_size.ToString() + "&filter.status=" + filter_status;
            string ApiUrl = "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks?"+postData;
            WebService ws = new WebService();
            string[] headers = new string[2];
            headers[0] = "Content-Type:application/json";
            headers[1] = "Authorization:Bearer " + ApiKey + "";
            ErrorMessage = "";
            ResultJson = "";
            string rs2 = ws.GetResponseResult(ApiUrl, Encoding.UTF8, "GET", "", headers);
            ErrorMessage = ws.ErrorMessage;
            ResultJson = rs2;            
}

成功调用后会返回如下示例:

XML 复制代码
{"total":5,"items":[
{"id":"cgt-2025","model":"doubao-seedance-1-0-pro-250528","
status":"succeeded",
"content":{"video_url":"https://ark"},"usage":{"completion_tokens":103818,"total_tokens":103818},"created_at":1763455989,"updated_at":1763456064,"seed":11,"resolution":"720p","ratio":"16:9","duration":5,"framespersecond":24},
{"id":"cgt-2025","model":"doubao-seedance-1-0-pro-250528",
"status":"succeeded",
"content":{"video_url":"https://ark"},"usage":{"completion_tokens":586092,"total_tokens":586092},"created_at":1763082221,"updated_at":1763082414,"seed":26522,"resolution":"1080p","ratio":"3:4","duration":12,"framespersecond":24},
{"id":"cgt-2025","model":"doubao-seedance-1-0-pro-250528",
"status":"succeeded",
"content":{"video_url":"https://arkt"},"usage":{"completion_tokens":586092,"total_tokens":586092},"created_at":1763082221,"updated_at":1763082446,"seed":81742,"resolution":"1080p","ratio":"3:4","duration":12,"framespersecond":24},
{"id":"cgt-2025","model":"doubao-seedance-1-0-pro-250528",
"status":"succeeded",
"content":{"video_url":"https://ark-"},"usage":{"completion_tokens":586092,"total_tokens":586092},"created_at":1763082221,"updated_at":1763082376,"seed":46824,"resolution":"1080p","ratio":"3:4","duration":12,"framespersecond":24},
{"id":"cgt-2025","model":"doubao-seedance-1-0-pro-250528",
"status":"succeeded",
"content":{"video_url":"https://ark"},"usage":{"completion_tokens":586092,"total_tokens":586092},"created_at":1763082221,"updated_at":1763082374,"seed":52271,"resolution":"1080p","ratio":"3:4","duration":12,"framespersecond":24}]}

可通过下列示例代码遍历生成的 videio_url (可访问视频):

cs 复制代码
string list = "";
Newtonsoft.Json.Linq.JObject rs2 = Newtonsoft.Json.Linq.JObject.Parse(ResultJson);
for (int i = 0; i < rs2["items"].Count(); i++)
{
    list+ = rs2["items"][i]["content"]["video_url"].ToString() + "\r\n";
}

红颜如霜

生成的视频效果还是有点意思,AI模型还是充分发挥了其想象力,对车辆情况的识别,行走的创意,变化的过度还算可以,毕竟只有12秒的时间。人物面部模型的五官部分稍微显得一点点 "拥挤" 变形,但真实还原度还是非常不错的。另外,要求加入的《红颜如霜》的音乐背景模型没有混入合成,不知是不是因为音乐版权的问题,于是自己录制了一首歌曲片断,使用手机视频编辑软件进行了编辑合成,最终效果如下视频:

AI模型生成的视频

小结

生成视频会消耗很多的 tokens,由于注册的时候使用的先用后付模式,发现体验生成视频模型后,帐户发生欠费,还请注意费用说明及消耗情况,满足自己的需求即可。

API的一些相关文档可以参考以下链接:

文档中心入口:

https://www.volcengine.com/docs/82379

创建视频生成任务 API:

https://www.volcengine.com/docs/82379/1520757

查询视频生成任务 API:

https://www.volcengine.com/docs/82379/1521309

查询视频生成任务列表:

https://www.volcengine.com/docs/82379/1521675

相关推荐
还不秃顶的计科生2 小时前
如何快速用cmd知道某个文件夹下的子文件以及子文件夹的这个目录分支具体的分支结构
人工智能
九河云2 小时前
不同级别华为云代理商的增值服务内容与质量差异分析
大数据·服务器·人工智能·科技·华为云
Elastic 中国社区官方博客3 小时前
Elasticsearch:Microsoft Azure AI Foundry Agent Service 中用于提供可靠信息和编排的上下文引擎
大数据·人工智能·elasticsearch·microsoft·搜索引擎·全文检索·azure
大模型真好玩3 小时前
Gemini3.0深度解析,它在重新定义智能,会是前端工程师噩梦吗?
人工智能·agent·deepseek
机器之心3 小时前
AI终于学会「读懂人心」,带飞DeepSeek R1,OpenAI o3等模型
人工智能·openai
AAA修煤气灶刘哥3 小时前
从Coze、Dify到Y-Agent Studio:我的Agent开发体验大升级
人工智能·低代码·agent
陈佬昔没带相机3 小时前
MiniMax M2 + Trae 编码评测:能否与 Claude 4.5 扳手腕?
前端·人工智能·ai编程
美狐美颜SDK开放平台3 小时前
从0到1开发直播美颜SDK:算法架构、模型部署与跨端适配指南
人工智能·架构·美颜sdk·直播美颜sdk·第三方美颜sdk·美狐美颜sdk
小陈phd3 小时前
RAG从入门到精通(四)——结构化数据读取与导入
人工智能·langchain
玖日大大3 小时前
Trae:字节跳动 AI 原生 IDE 的技术革命与实战指南
ide·人工智能