c#操作CCtalk视频下载

Posted 哲虎

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c#操作CCtalk视频下载相关的知识,希望对你有一定的参考价值。

郑重声明: 本人已购买该付费课程, 必须提前购买课程才可以下载。不是广告!

写这篇文章的目的是为了方便在本地播放和保存视频.

流程

  1. 获取播放列表
  2. 通过播放列表获取视频地址并生成Aria2c批量下载URL(指定文件名)
  3. 使用Aria2c进行下载视频

开始分析

打开DevTools,进入已购买的课程页面,点击开始学习按钮,在DevTools筛选器上搜索all_lesson_list


此时获取到了一个URL,这个连接是所有课程数据列表,https://www.cctalk.com/webapi/content/v1.2/series/all_lesson_list?seriesId=1648563754438470&limit=&showStudyTime=false&_timestamp=1663807475982 seriesId=1648563754438470是课程ID在下面URL中使用。

继续通过分析从该链接https://www.cctalk.com/webapi/content/v1.1/series/1648563754438470/get_content_unit_struts获取json数据,该数据中contentIdList就是所有课程视频ID => videoId


	"data": 
		"seriesId": 1648563754438470,
		"showType": 0,
		"totalCount": 83,
		"unitList": [
			"contentIdList": [
				16486908151117,
				 ......
			],
			"unitId": 0
		]
	,
	"message": "success",
	"status": 0,
	"time": "2022-09-22T09:24:25+0800"

通过上面的数据获取到了必要参数后,现在需要获取单个视频的json数据,经过分析发现通过该URLhttps://www.cctalk.com/webapi/content/v1.1/video/detail?videoId=16486908151117&seriesId=1648563754438470 可以获取到视频信息。

  • videoId=16486908151117 视频ID
  • seriesId=1648563754438470 课程ID

这2个参数是从上面步骤获取到的.

返回数据如下,在这里核心数据为videoUrl这个是视频URL,通过访问该URL可以在线播放,也可以下载视频.同时也需要videoName它是视频标题,使用它在下面下载视频保存文件时指定文件名.


	"data": 
		"adEnable": true,
		"collectInfo": 
			"collectCount": 2,
			"collectStatus": 0,
			"collectionContentId": 5096,
			"contentId": 16486908151117,
			"contentType": 1
		,
		"companyId": 0,
		"coursewareInfo": 
			"coursewareId": "1509184337896175193",
			"ocsStatus": 0,
			"tenantId": 10002,
			"userSign": "K0JPWgQeSLvrlK551YiXHo3Xuq/TnKdqQ3sTnwo4LVUXcIN4HGEBPvvXtvGKsjPN1LVV+290fyfn2MGBdIu3jrlJxZ9f5JZeTmFbAPRSQ62rIgTK0hqizoUr+jyx+ne77tLjdTNQQd4ISF7XpJ+lsspshn6gu9dIB0T634KPiBEPMheGNHXq6xkEv3dE3aqtXTbPvzWGk27ezVG5qHpAlu8eTdIsAhepVtc5uF4fsPYopKlbXujRYRlg1NVUmdPXHOX3/gg8yFzpxDEb2u/pC5XFkYYJ5ztdBGtxA7r1OoSmMg/b2JaOenmkrd/Cze2PxBEWKt7PM2AUphUMwm0re6EeAf2aw5TlFksl6+WkCcxkSoUtVtw6ValjGo5AxWieNc5itJpA8OQ8TenBiBhikvrQiToJBh5Aw1QvfhgAVht7LcOUDOhFd2wAEJRoZMuPkGOAbixXVhV/5i9+80lg/3WXrRuCi8lDkn1W+NPsCVvDh0P8WKX3teCgfBXYR9Gl"
		,
		"coverUrl": "https://cc.hjfile.cn/cc/img/20220330/2022033011024002972564.jpg",
		"createUserId": xxxxxx,
		"enableCache": 1,
		"feedbackInfo": 
			"haveFeedback": 0
		,
		"groupId": 90268531,
		"groupIsActive": 1,
		"groupName": "vol框架开发实战讲解.NetCore vue  uni-app",
		"hideRating": false,
		"hideReserveButton": false,
		"intro": 
			"section": [
				"contentStruct": ,
				"contents": []
			]
		,
		"isCharge": 1,
		"isGroupMember": true,
		"isOpenProtection": false,
		"isReserve": true,
		"isTrial": false,
		"knowledgeList": [],
		"likeCount": 2,
		"likeStatus": 0,
		"liveNum": 0,
		"liveStartDate": "2022-03-31T09:40:15+0800",
		"liveStatus": 11,
		"logo": "vol",
		"logoShowStatus": 0,
		"mediaTotalTime": 411000,
		"openType": 1,
		"pagePermission": 1,
		"playCount": 1881,
		"playPermission": 1,
		"ratingCount": 6,
		"reserveCount": 0,
		"reviewStatus": 21,
		"seriesInfo": 
			"coverUrl": "https://cc.hjfile.cn/cc/img/20220329/2022032910204179033032.jpg",
			"hasSubscribe": true,
			"seriesId": 1648563754438470,
			"seriesName": "vol框架视频",
			"subscribeCount": 336,
			"videoCount": 83
		,
		"showRecommend": false,
		"starAvg": 5.0,
		"studyPosition": 0,
		"taskInfo": ,
		"totalSize": 40894464,
		"trialDuration": -1,
		"userCard": 
			"avatar": "https://i2n.hjfile.cn/u/default/ext/200/5.jpg",
			"followedMeCount": 366,
			"nickName": "vol",
			"relationStatus": 1,
			"summary": "多年.net、vue前后端分离开发经验.",
			"userId": xxxxxx,
			"userName": "QQ用户xxxx"
		,
		"videoCut": 0,
		"videoEndDate": "2022-03-31T09:47:06+0800",
		"videoId": 16486908151117,
		"videoName": "框架介绍",
		"videoStartDate": "2022-03-31T09:40:15+0800",
		"videoType": 0,
		"videoUrl": "https://record-manual.cctalk.com/5285d79daf63dd321eb89d912a9236d5.mp4?auth_key=1663823958-58b24996728341e69d9ec573d356f669-0-0606fbe337ddd193046cff6ffc121ee9"
	,
	"message": "success",
	"status": 0

到目前为止已经完成了基本的分析,下面开始写代码


c#代码

在下面代码中需要填写2个参数,第一个是填写自己的COOKIE,使用自己的账号登录后,从浏览器中复制cookie,第二个是课程ID,await Getcourse("1648563754438470"); 这里传递的参数是课程ID

使用nuget添加以下2个扩展,同时本地需要安装redis数据库,如果没有可以改代码,使用SortedList代替redis

  • StackExchange.Redis
  • Newtonsoft.Json

Program.cs

// See https://aka.ms/new-console-template for more information

using StackExchange.Redis;
using System.Net.Http.Headers;
using System.Net;
using Newtonsoft.Json;
using System;
using Newtonsoft.Json.Converters;
using System.Globalization;
using System;
using System.Collections.Generic;
using static CCtalk.Program;

namespace CCtalk


    class Program
    
        public static string global_cookies = "填写自己的COOKIE";//使用自己的账号登录后,从浏览器中复制cookie
 
        //连接redis服务器
        public static ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");

        //获取redis数据库
        public static IDatabase db = redis.GetDatabase();

        static async Task Main(string[] args)
        
 
            //获取课程所有视频ID
            await Getcourse("1648563754438470");

            //获取最终视频播放地址并把地址写入txt文件,最后使用aria2c工具进行批量下载
            await Getcontent();
 
        

        /// <summary>
        /// 获取最终视频播放地址并把地址写入txt文件,最后使用aria2c工具进行批量下载
        /// </summary>
        /// <returns></returns>
        public static async Task Getcontent()
        
            //获取桌面路径
            string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

            //在桌面生成cctalk.txt文件
            using (FileStream fs = new FileStream(desktopPath + @"\\cctalk.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
            
                using (StreamWriter sw = new StreamWriter(fs))
                
                    //获取redis数据
                    var full_redis_json_data = await db.HashGetAllAsync("cctalk_contentIdLists");
                    
                    //遍历数据
                    foreach (var item in full_redis_json_data)
                    
                        //获取单个视频JSON数据,提取VideoName和videoUrl
                        var result = await Browser(item.Value.ToString());
                        
                        //解析json数据
                        var contents = Contents.FromJson(result);

                        //把数据保存到redis数据库,进行备份操作,方便后续使用,也可以使用自己编写代码进行下载视频.
                        // key为1. 框架介绍.mp4,value为最终视频URL地址
                        await db.HashSetAsync("cctalk_VideoLists", item.Name.ToString() + "." + contents.Data.VideoName.ToString() + ".mp4", contents.Data.VideoUrl.ToString());

                        //把数据写入txt文件,输入格式为Aria2c下载格式并指定文件名
                        Task task = sw.WriteLineAsync(contents.Data.VideoUrl.ToString() + "\\r\\n" + " out=" + item.Name.ToString() + "." + contents.Data.VideoName.ToString() + ".mp4");

                    
                

            

        


        /// <summary>
        /// 获取课程所有视频ID
        /// </summary>
        /// <param name="seriesId">课程ID</param>
        /// <returns></returns>
        public static async Task Getcourse(string seriesId)
        
            var kechengURL = "https://www.cctalk.com/webapi/content/v1.1/series/" + seriesId.ToString() + "/get_content_unit_struts";
            
            string url_begin = "https://www.cctalk.com/webapi/content/v1.1/video/detail?videoId=";
            string url_end = "&seriesId="+ seriesId.ToString()+ "&_timestamp=1663738877186";

            //获取JSON数据
            var result = await Browser(kechengURL);
            
            //解析JSON数据
            var course = Course.FromJson(result);
 
            var i = 1;
            //遍历course,获取所有视频ID
            foreach (var item in course.Data.UnitList[0].ContentIdList)
            
               //拼接完整单个视频访问URL地址
                var final_url = url_begin + item.ToString() + url_end;
                
                //将视频ID和完整URL存入redis数据库, key为i,value为完整URL地址
                var redis_hastset = await db.HashSetAsync("cctalk_contentIdLists", i.ToString(), final_url.ToString());
      
                i += 1;
            

        

        public partial class Course
        
            [JsonProperty("data")]
            public Data Data  get; set; 

            [JsonProperty("message")]
            public string Message  get; set; 

            [JsonProperty("status")]
            public long Status  get; set; 

            [JsonProperty("time")]
            public string Time  get; set; 
        

        public partial class Data
        
            [JsonProperty("seriesId")]
            public long SeriesId  get; set; 

            [JsonProperty("showType")]
            public long ShowType  get; set; 

            [JsonProperty("totalCount")]
            public long TotalCount  get; set; 

            [JsonProperty("unitList")]
            public UnitList[] UnitList  get; set; 
        

        public partial class UnitList
        
            [JsonProperty("contentIdList")]
            public long[] ContentIdList  get; set; 

            [JsonProperty("unitId")]
            public long UnitId  get; set; 
        

        public partial class Course
        
            public static Course FromJson(string json) => JsonConvert.DeserializeObject<Course>(json,  Converter.Settings);
        

        public partial class Contents
        
            [JsonProperty("data")]
            public Data Data  get; set; 

            [JsonProperty("message")]
            public string Message  get; set; 

            [JsonProperty("status")]
            public long Status  get; set; 
        

        public partial class Data
        
            [JsonProperty("adEnable")]
            public bool AdEnable  get; set; 

            [JsonProperty("collectInfo")]
            public CollectInfo CollectInfo  get; set; 

            [JsonProperty("companyId")]
            public long CompanyId  get; set; 

            [JsonProperty("coursewareInfo")]
            public CoursewareInfo CoursewareInfo  get; set; 

            [JsonProperty("coverUrl")]
            public Uri CoverUrl  get; set; 

            [JsonProperty("createUserId")]
            public long CreateUserId  get; set; 

            [JsonProperty("enableCache")]
            public long EnableCache  get; set; 

            [JsonProperty("feedbackInfo")]
            public FeedbackInfo FeedbackInfo  get; set; 

            [JsonProperty("groupId")]
            public long GroupId  get; set; 

            [JsonProperty("groupIsActive")]
            public long GroupIsActive  get; set; 

            [JsonProperty("groupName")]
            public string GroupName  get; set; 

            [JsonProperty("hideRating")]
            public bool HideRating  get; set; 

            [JsonProperty("hideReserveButton")]
            public bool HideReserveButton  get; set; 

            [JsonProperty("intro")]
            public Intro Intro  get; set; 

            [JsonProperty("isCharge")]
            public long IsCharge  get; set; 

            [

带有联合和数组的 C# pinvoke 结构

【中文标题】带有联合和数组的 C# pinvoke 结构【英文标题】:C# pinvoke structs with union and arrays 【发布时间】:2013-11-28 20:28:27 【问题描述】:

我无法定义正确的 C# 代码以使用 C++ 库,该库定义了一个具有联合和数组的复杂结构,我在执行 C++ 代码时不断收到一些内存异常,我很确定这是由于这个原因。

c++ 结构如下,忽略枚举和其他结构定义(如果需要我会发布它们,但它们非常丰富)

typedef struct

DG_CCTALK_APP_EVT_CODE  eEventCode;
DG_CCTALK_APP_EVT_TYPE  eEventType;
int         iTime;
int         iHandle;
unsigned char       uchAddress;
DG_CCTALK_BILL_INFO sBillInfo;
int         iBillAmount;
union

    long        lData;
    int     iData;
    unsigned char   ucArray[128];
    char        *cString;
    void        *pvoid;
 uData;
void            *_private;  // for use by cctalk app layer
 DG_CCTALK_APP_EVT, *PDG_CCTALK_APP_EVT;

C# 代码是这样的:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)]
    public struct Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
    
        //deberian llevar todos 0, pero el array genera problemas al ponerle 0, y cambiandolo explota en otro lado...

        /// int
        [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
        public int lData;

        /// int
        [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
        public int iData;

        /// unsigned char[128]
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 128, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I1)]
        [System.Runtime.InteropServices.FieldOffsetAttribute(4)]
        public byte[] ucArray;

        /// char*
        [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
        public System.IntPtr cString;

        /// void*
        [System.Runtime.InteropServices.FieldOffsetAttribute(0)]
        public System.IntPtr pvoid;
    

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct DG_CCTALK_APP_EVT
    

        /// DG_CCTALK_APP_EVT_CODE->_DG_CCTALK_APP_EVT_CODE
        public DG_CCTALK_APP_EVT_CODE eEventCode;

        /// DG_CCTALK_APP_EVT_TYPE->_DG_CCTALK_APP_EVT_TYPE
        public DG_CCTALK_APP_EVT_TYPE eEventType;

        /// int
        public int iTime;

        /// int
        public int iHandle;

        /// unsigned char
        public byte uchAddress;

        /// DG_CCTALK_BILL_INFO->_DG_CCTALK_BILL_INFO
        public DG_CCTALK_BILL_INFO sBillInfo;

        /// int
        public int iBillAmount;

        /// Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40
        public Anonymous_92d21a81_2a8b_42f4_af32_f7606aa9cf40 uData;

        /// void*
        public System.IntPtr _private;
    

委托和函数导入

public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);

[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_enable_device", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_enable_device(ref DG_CCTALK_APP_EVT param0);

更新:asnwer 之后的新代码,仍然无法正常工作: 错误是:“尝试读取或写入受保护的内存这通常表明其他内存已损坏”

奇怪的是,我可以在第一次事件调用时使用该结构,我打印所有字段并且它们似乎是正确的(lData 和 iData 具有相同的值,cData 有一个我发送的字符串)但是在事件之后结束程序死亡。好像我的 C# 代码破坏了结构或其他东西......

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
    public struct DG_CCTALK_APP_EVT
    

        /// DG_CCTALK_APP_EVT_CODE->_DG_CCTALK_APP_EVT_CODE
        public DG_CCTALK_APP_EVT_CODE eEventCode;

        /// DG_CCTALK_APP_EVT_TYPE->_DG_CCTALK_APP_EVT_TYPE
        public DG_CCTALK_APP_EVT_TYPE eEventType;

        /// int
        public int iTime;

        /// int
        public int iHandle;

        /// unsigned char
        public byte uchAddress;

        /// DG_CCTALK_BILL_INFO->_DG_CCTALK_BILL_INFO
        public DG_CCTALK_BILL_INFO sBillInfo;

        /// int            
        public int iBillAmount;            

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        public byte[] uData;

        #region setters y getters para mapeo

        public int lData
        
            set
            
                Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
            
            get
            
                return BitConverter.ToInt32(uData, 0);
            
        

        public int iData
        
            set
            
                Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));
            
            get
            
                return BitConverter.ToInt32(uData, 0);
            
        

        public byte[] ucArray
        
            set
            
                Array.Copy(value, uData, 128);
            
            get
            
                return uData;

            
        

        public IntPtr cString
        
            set
            
                Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
            
            get
            
                return (IntPtr)BitConverter.ToInt32(uData, 0);
            
        

        public IntPtr pvoid
        
            set
            
                Array.Copy(BitConverter.GetBytes(value.ToInt32()), uData, 32);
            
            get
            
                return (IntPtr)BitConverter.ToInt32(uData, 0);
            
        


        #endregion

        /// void*
        public System.IntPtr _private;
    

C++ 声明:

typedef void (*DG_CCTALK_APP_EVT_HANDLER)(PDG_CCTALK_APP_EVT pEVT);

DGCCTALK_PREFIX DG_ERROR cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);
DGCCTALK_PREFIX DG_ERROR cctalk_app_add_link(char *szPortName);

注意爸爸DGCCTALK_PREFIX被定义为__declspec(dllexport)

C# 代码:

public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);

[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint =     "cctalk_app_init", CallingConvention = CallingConvention.Cdecl)]
 public static extern int cctalk_app_init(DG_CCTALK_APP_EVT_HANDLER pfnHandler);

[System.Runtime.InteropServices.DllImportAttribute("cctalk.dll", EntryPoint = "cctalk_app_add_link", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_add_link(System.IntPtr szPortName);

调用它们的 C# 代码

var handler = new DG_CCTALK_APP_EVT_HANDLER(this._handler);
var resultado = cctalk_app_init(handler);
cctalk_app_add_link(Marshal.StringToHGlobalAnsi("port=" + port));

C# 处理程序头

private void _handler(ref DG_CCTALK_APP_EVT pEVT)

【问题讨论】:

为什么使用 4 的偏移量?错误是什么?怎么调用函数? 原来是0,但是会导致无效aling异常。我这里没有错误,但它是关于访问程序没有读/写权限的内存。 另外我没有显式调用这个结构的方法,它实际上是一个从 c++ 库中触发的事件,它向我发送这个结构(这里没有错误),但是在事件完成后,作为 c++代码再次运行,它中断了。 所以不要费心定义联合。并使用 Marshal 类来挑选字段。仅将 0 更改为 4 不是答案。 不接收 ref 的结构。接收一个 IntPtr。然后手动挑选你需要的东西。 【参考方案1】:

正如您所发现的,封送拆收器不喜欢您在翻译联合时尝试将数组与其他字段重叠。您通过将数组的偏移量更改为 4 而不是 0 来抑制问题。但这无济于事。

现在,由于 marshaler 不会为您处理联合,因此您必须手动完成。我会通过省略联合的非数组成员来处理这个问题。

[StructLayout(LayoutKind.Sequential)]
public struct DG_CCTALK_APP_EVT

    public DG_CCTALK_APP_EVT_CODE eEventCode;
    public DG_CCTALK_APP_EVT_TYPE eEventType;
    public int iTime;
    public int iHandle;
    public byte uchAddress;
    public DG_CCTALK_BILL_INFO sBillInfo;
    public int iBillAmount;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public byte[] uData;
    public IntPtr _private;

请注意,我已经删除了您声明的大部分冗长。我怀疑该类型是由工具自动生成的。但是所有这些冗长使得它很难阅读。

这将为结构生成正确的布局,但会让您有工作要做以访问联合中的其他字段。

那么,我们如何读取这些字段?好吧,数据包含在字节数组uData 中,所以只需从那里读取值。例如,您可以将以下属性添加到 DG_CCTALK_APP_EVT 结构:

public int lData

    get  return BitConverter.ToInt32(uData, 0); 
    set  uData = BitConverter.GetBytes(value); 


public int iData

    get  return BitConverter.ToInt32(uData, 0); 
    set  uData = BitConverter.GetBytes(value); 


// etc.

请注意,setter 将清除数组中除前 4 个字节之外的所有字节,因为它会覆盖 uData。我对本机代码的协议知之甚少,无法确定这是您想要的。如果这不是您想要的,那么您可以这样编写 setter:

Array.Copy(BitConverter.GetBytes(value), uData, sizeof(int));

您现在已经添加了互操作边界的 C++ 端。最明显的问题是您的 C# 委托似乎有错误的调用约定。它使用stdcall,但C++ 代码需要cdecl。这当然足以解释回调返回后发生的灾难性崩溃。您需要确保您的委托指定调用约定。

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DG_CCTALK_APP_EVT_HANDLER(ref DG_CCTALK_APP_EVT pEVT);

您对cctalk_app_add_link 的翻译也是错误的。应该是:

[DllImport("cctalk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int cctalk_app_add_link(string szPortName);

这样做,您可以简单地传递一个字符串,从而避免您当前实现的内存泄漏。

【讨论】:

您将 SizeConst 变量设置为 128,但这只会保存 uData union 中定义的数组,那么其他字段呢?它实际上不应该更大吗? lData 4 个字节(或 8 个字节,因为它很长?)| iData 4 个字节 ucArray 128 个字节 cString 4 个字节(如果在 64 位机器上工作,则为 8 个,因为它是一个指针) pvoid 4 个字节(同上) 我已经更新了我的问题,用你的答案,但它仍然不起作用,我真的迷路了。 不,工会覆盖成员。因此,您的工具生成的所有成员的 FieldOffset 为 0。我不太确定这里的“不起作用”是什么意思。你没有照我说的去做。您的代码有 144 而不是 128。 所有的 getter 和 setter 都需要在数组的开头工作。你应该再读一遍到底什么是联合。 IntPtr 怎么样?我该如何管理它们?我的演员表是否正确(假设我只在 32 位机器上工作)【参考方案2】:

检查您的 int 和 long 字段。 我认为 C int 是 16 位,而 C# int 是 32:

如果是这样,那么 iTime、iHandle 和 iBilAmount 在 C# 和 C 定义中都被定义为 int。 如果我错了,那么 lData 在 C 中定义为 long 而在 C# 中定义为 int(如果这是问题所在,那么不要忘记修复出现在 lData 之后)。

【讨论】:

不。在 Windows 上,C++ int 是 32 位 这是一个工会!偏移量均为 0。无需固定。在 Windows 上的 C++ 中,int 和 long 是 4 个字节宽。 对不起,你是对的。错过了128长的数组,没看出他用的是windows。

以上是关于c#操作CCtalk视频下载的主要内容,如果未能解决你的问题,请参考以下文章

iKcamp|基于Koa2搭建Node.js实战(含视频)? 错误处理

C#通用平台音频合并或输入视频

C#进程调用FFmpeg操作音视频

iKcamp|基于Koa2搭建Node.js实战(含视频)? 代码分层

C#怎么将Json转成能用的

C#入门视频教程,C#语言入门详解,限时免费领取!