学习笔记- AVFoundation Programming Guide - Using Assets

玩转iOS开发:使用AVFoundation实现扫码 在iOS7当中, Apple就已经在AVFoundation当中加入对扫码的支持, 大家从此就可以和ZXing说拜拜了, 也感谢ZXing长期以来为我们提供扫码的功能. 阅读详情

Using Assets

Assets 能来自一个文件或者来自用户iPos库或照片库的多媒体文件。当你创建一个asset 对象时,所有你可能要检索的信息不是立即可用的。

一旦你有了一个视频asset,你可以提取静态图像,转换成另一种格式,或内容裁减。


1. Creating an Asset Object

通过URL创建asset,可以试用AVURLAsset。创建asset最简单的方式是通过一个文件。

code:

NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];


2. Options for Initalizing an Asset

AVURLAsset初始化方法的第二个参数使用一个dictionary,这个dictionary里的唯一一个key是 AVURLAssetPreferPreciseDurationAndTimingKey。它的value是一个boolean类型(用NSValue包装的对象),这个值表示asset是否提供一个精确的duration。
获取asset精确的duration需要很多处理时间,使用一个预估的duration效率比较高并且对播放来说足够。因此:
. 如果你想要播放asset,初始化方法传nil就行了,而不是一个dictionry,或者传一个以AVURLAssetPreferPreciseDurationAndTimingKeydictionary为key,值为NO的一个dictionary。
. 如果你想把asset加到一个composition中,你需要一个精确的访问权限,这时你可以传一个dictionary,这个dictionary的一组键值对为AVURLAssetPreferPreciseDurationAndTimingKey和YES。
code:

NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;
NSDictionary *options = @{ AVURLAssetPreferPreciseDurationAndTimingKey : @YES };
AVURLAsset *anAssetToUseInAComposition = [[AVURLAsset alloc] initWithURL:url options:options];


3. Accessing the User's Assets

为了访问iPod Library 和相册里的asset,需要获取asset 的URL。

. 为了访问iPod Library,需要创建MPMediaQuery对象来找到想要的对象,然后通过MPMediaItemPropertyAssetURL获取它的URL。

. 为了访问相册,可以试用ALAssetsLibrary。

code:

// 下面的代码用来获取相册里面的第一个视频

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
 
// Within the group enumeration block, filter to enumerate just videos.
[group setAssetsFilter:[ALAssetsFilter allVideos]];
 
// For this example, we're only interested in the first item.
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:0]
                        options:0
                     usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {
 
                         // The end of the enumeration is signaled by asset == nil.
                         if (alAsset) {
                             ALAssetRepresentation *representation = [alAsset defaultRepresentation];
                             NSURL *url = [representation url];
                             AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
                             // Do something interesting with the AV asset.
                         }
                     }];
                 }
                 failureBlock: ^(NSError *error) {
                     // Typically you should handle an error more gracefully than this.
                     NSLog(@"No groups");
                 }];


4. Preparing an Asset for Use

初始化一个asset(或者track)并不是表示asset里面所有的信息都是马上可用的。它需要一些时间去计算,即使是durtation(比如没有摘要信息的mp3文件),你应该使用AVAsynchronousKeyValueLoading协议获取这些值,通过- loadValuesAsynchronouslyForKeys:completionHandler:在handler里面获取你要的值。
你可以用statusOfValueForKey:error:测试一个属性的value是否成功获取,当一个assert第一次被加载,大多数属性的值是AVKeyValueStatusUnknown状态,为了获取一个或多个属性的值,你要调用loadValuesAsynchronouslyForKeys:completionHandler:,在comletiton handler里面,你可以根据属性的状态做任何合适的处理。你要处理加载没有成功的情况,可能因为一些原因比如网络不可连接,又或者loading被取消。

code:

NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
NSArray *keys = @[@"duration"];
 
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^() {
 
    NSError *error = nil;
    AVKeyValueStatus tracksStatus = [asset statusOfValueForKey:@"duration" error:&error];
    switch (tracksStatus) {
        case AVKeyValueStatusLoaded:
            [self updateUserInterfaceForDuration];
            break;
        case AVKeyValueStatusFailed:
            [self reportError:error forAsset:asset];
            break;
        case AVKeyValueStatusCancelled:
            // Do whatever is appropriate for cancelation.
            break;
   }
}];


5. Getting Still Images From a Video

从播放的asset中获取静态图片比如缩略图,你可以用AVAssetImageGenerator对象。

可以用asset初始化一个AVAssetImageGenerator对象。即使asset在初始化的时候没有可见的track也能成功,所以你应该检测asset是否有track,使用tracksWithMediaCharacteristic:

code:

AVAsset anAsset = <#Get an asset#>;
if ([[anAsset tracksWithMediaType:AVMediaTypeVideo] count] > 0) {
    AVAssetImageGenerator *imageGenerator =
        [AVAssetImageGenerator assetImageGeneratorWithAsset:anAsset];
    // Implementation continues...
}

你还可以设置imagegenerator的其他属性,比如,你可以指定生成图片的最大的分辨率,你可以生成指定时间的一张图片,或者一系列图片。你必须一直持有generator的引用,直到生成所有的图片。


6. Generating a Single Image

你可以使用copyCGImageAtTime:actualTime:error:生成一张指定时间点的图片。AVFoundation不一定能精确的生成一张你所指定时间的图片,所以你可以在第二个参数传一个CMTime的指针,用来获取所生成图片的精确时间。

code:

AVAsset *myAsset = <#An asset#>];
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:myAsset];
 
Float64 durationSeconds = CMTimeGetSeconds([myAsset duration]);
CMTime midpoint = CMTimeMakeWithSeconds(durationSeconds/2.0, 600);
NSError *error;
CMTime actualTime;
 
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:midpoint actualTime:&actualTime error:&error];
 
if (halfWayImage != NULL) {
 
    NSString *actualTimeString = (NSString *)CMTimeCopyDescription(NULL, actualTime);
    NSString *requestedTimeString = (NSString *)CMTimeCopyDescription(NULL, midpoint);
    NSLog(@"Got halfWayImage: Asked for %@, got %@", requestedTimeString, actualTimeString);
 
    // Do something interesting with the image.
    CGImageRelease(halfWayImage);
}


7. Generating a Sequence of Images

为了生成一系列图片,你可以调用generateCGImagesAsynchronouslyForTimes:completionHandler:。第一个参数是一个包含NSValue类型的数组,数组里每一个对象都是CMTime结构体,表示你想要生成的图片在视频中的时间点,第二个参数是一个block,每生成一张图片都会回调这个block,这个block提供一个result的参数告诉你图片是否成功生成或者图片生成操作是否取消。

在你的block实现中,需要检查result,判断image是否成功生成,另外,确保你持有image generator直到生成图片的操作结束。

code:

AVAsset *myAsset = <#An asset#>];
// Assume: @property (strong) AVAssetImageGenerator *imageGenerator;
self.imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:myAsset];
 
Float64 durationSeconds = CMTimeGetSeconds([myAsset duration]);
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 600);
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 600);
CMTime end = CMTimeMakeWithSeconds(durationSeconds, 600);
NSArray *times = @[NSValue valueWithCMTime:kCMTimeZero],
                  [NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird],
                  [NSValue valueWithCMTime:end]];
 
[imageGenerator generateCGImagesAsynchronouslyForTimes:times
                completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime,
                                    AVAssetImageGeneratorResult result, NSError *error) {
 
                NSString *requestedTimeString = (NSString *)
                    CFBridgingRelease(CMTimeCopyDescription(NULL, requestedTime));
                NSString *actualTimeString = (NSString *)
                    CFBridgingRelease(CMTimeCopyDescription(NULL, actualTime));
                NSLog(@"Requested: %@; actual %@", requestedTimeString, actualTimeString);
 
                if (result == AVAssetImageGeneratorSucceeded) {
                    // Do something interesting with the image.
                }
 
                if (result == AVAssetImageGeneratorFailed) {
                    NSLog(@"Failed with error: %@", [error localizedDescription]);
                }
                if (result == AVAssetImageGeneratorCancelled) {
                    NSLog(@"Canceled");
                }
  }];

你可以通过发送 cancelAllCGImageGeneration消息取消生成图片序列的操作。


8. Trimming and Transcoding a Movie

你可以对视频进行转码、裁剪,通过使用AVAssetExportSession对象。

一个export session是一个控制对象,可以异步的生成一个asset。可以用你需要生成的asset和presetName来初始化一个session,presetName指明你要生成的asset的属性。接下来你可以配置export session,比如可以指定输出的URL和文件类型,以及其他的设置,比如metadata和是否输出应优化网络试用。
你可以先检测设置的preset是否可用,通过使用exportPresetsCompatibleWithAsset:方法。

code:

AVAsset *anAsset = <#Get an asset#>;
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:anAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
        initWithAsset:anAsset presetName:AVAssetExportPresetLowQuality];
    // Implementation continues.
}

你可以配置session的输出的url(这个url必须是文件url),AVAssetExportSession可以通过url的扩展名推断出输出文件的类型。当然,你可以直接设置文件类型,使用outputFileType。你还可以指定其他属性,比如time range,输出文件的长度,是否应该对导出的文件进行网络优化,以及视频合成。

code:

// 试用时间范围修剪视频

    exportSession.outputURL = <#A file URL#>;
    exportSession.outputFileType = AVFileTypeQuickTimeMovie;
 
    CMTime start = CMTimeMakeWithSeconds(1.0, 600);
    CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
    CMTimeRange range = CMTimeRangeMake(start, duration);
    exportSession.timeRange = range;

生成一个新的asset,可以调用exportAsynchronouslyWithCompletionHandler:,当生成操作结束后会回调block,在这个block中你需要通过检查session的status来判断是否成功,如下:

[exportSession exportAsynchronouslyWithCompletionHandler:^{
        switch ([exportSession status]) {
            case AVAssetExportSessionStatusFailed:
                NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
                break;
            case AVAssetExportSessionStatusCancelled:
                NSLog(@"Export canceled");
                break;
            default:
                break;
        }
    }];


你可以取消这个生成操作,通过给session发送 cancelExport 消息。
如果导出的文件存在,或者导出的url在沙盒之外,这个导出操作会失败。还有两种情况也可能导致失败:
· 来了一个电话
· 你的程序在后台运行并且其他的应用开始播放。
这种情况下,你应该通知用户export失败,并且重新export。



swift-使用进行短视频拍摄和播放 使用进行短视频拍摄和播放 立即下载

相关推荐

程序化广告行业(2/89):从程序化广告深挖数据处理技巧

大家好!我一直希望能和大家在技术学习的道路上携手共进,这也是我写这一系列博客的初衷。上次我们一起学习了Python基础的数据处理知识,这次咱们借助一本程序化广告手册,深入挖掘数据处理的更多技巧。这本手册涵盖了程序化广告从概念到技术实现的诸多方面,而其中处处都涉及到数据处理,相信会给我们带来不少收获

yyy173611的博客 4571

视频转图片序列 java_视频和图片序列帧互相转换

如果你有一些连续的图片序列,那么把它转换成MP4再放到网络上传输是一个好的选择,因为size会小很多。从视频里面抽取连续的图片序列也是一个偶尔会遇到的问题。我分别尝试使用iOS原生的API,FFmpeg和OpenCV来解决这两个问题。1、原生方法使用原生方法主要是利用AVFoundation框架的api进行转换的。1、将视频解成序列帧- (NSError *)nativeTransferMovie...

weixin_39616003的博客 898

学习笔记【Day 20】鸿蒙PC应用在SD WAN MSTP场景用CodeArts test工具测试过程

多生成树协议(MSTP)作为二层网络高可靠、无环路的核心技术,其在鸿蒙 PC 上的兼容性与稳定性测试尤为重要。本文结合华为云 CodeArts TestPlan 全流程测试管理平台,详细拆解鸿蒙 PC 端 MSTP 功能的测试设计、环境搭建、执行验证。1.测试左移,保障迭代效率CodeArts TestPlan 将 MSTP 测试从后期集成阶段 “左移” 至开发早期,通过可复用用例库与自动化脚本,支持每次代码提交后的快速回归测试,避免网络功能稳定性因迭代被破坏。2.平台化工具破解复杂场景测试难题。

aiyijianghe的博客 1057

AVAssetImageGenerator 的理解和使用

AVAssetImageGenerator 是用来提供视频的缩略图或预览视频的帧的类.可以用AVAsset来初始化: initWithAsset:  或assetImageGeneratorWithAsset:(生成图片的真正时间可能在requestedTimeToleranceBefore 和 requestedTimeToleranceAfter之间,也可能和请求时间无关.)可以用异步方法获取...

时光的博客 5727

银河麒麟Arm64 v10 sp1系统QT5.12.8离线环境配置全攻略

本文详细介绍了在银河麒麟Arm64 v10 sp1系统上配置QT5.12.8离线开发环境的完整流程。从安装包获取、依赖检查到环境变量配置,逐步指导开发者解决飞腾处理器架构下的常见问题,包括OpenGL库冲突、中文乱码处理等,特别适合军工、政务等需要离线部署的场景。

weixin_26899659的博客 504

samba源码编译安装(版本4.13.0)

这里写目录标题前言编译安装samba下载三个包安装依赖共需要安装samba、gnutls、nettle1、进入解压后的samba目录执行:2、进入解压后的gnutls目录执行3、进入解压后的nettle目录执行3.1 卸载已存在nettle3.2 编译3.3 make3.4 安装4、进入gnutls继续编译4.1 编译4.2 make4.3 安装5、再次进入解压后的samba目录5.1 执行./configure5.2 make5.3 samba安装启动samba 前言 一般来说,安装samba最快的方式应

灵葱的博客 1万+

AVAssetImageGenerator(获取视频关键帧)

如果我们有一个AVAsset,我们可以通过AVAssetImageGenerator这个类来生成图片.来作为预览图使用.使用起来也特别简单. self.imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:self.asset]; CMTime actualTime; CGImageRef cgImage = [s...

MeteoriteMan的博客 1482

14 硬件工程师笔面试高频考点真题解析——逻辑门

逻辑门是数字电路的基本单元,实现布尔运算(如与、或、非、异或等)。OC门(集电极开路)和OD门(漏极开路)需外接上拉电阻,支持“线与”逻辑,适用于I2C总线等场景,避免推挽输出并联导致的短路问题。三态门具有高、低、高阻三种状态,用于总线分时复用。推挽输出因内置上下管,禁止并联,否则会引发电源短路。三者区别在于:推挽驱动强但不可并联;OC/OD需上拉,支持线与;三态门通过使能控制实现高阻隔离,适用于共享总线设计。

XU157303764的博客 1897

AVFoundation Programming Guide - Using Assets

Using Assets Assets can come from a file or from media in the user’s iPod library or Photo library. When you create an asset object all the information that you might want to retrieve for t

欢迎来到Jack的程序世界 694

因果强化学习:优化决策策略的因果方法

1. 背景介绍 1.1 传统强化学习的局限性 强化学习(Reinforcement Learning, RL)是一种通过与环境交互来学习最优决策策略的方法。然而,传统强化学习方法在面对复杂、动态和不确定的现实世界问题时,往往存在以下局限性: 数据效率低:传统强化学习方法

AI天才研究院 655

Python爬虫实战:高效爬取中国版权登记数据

本文将详细介绍如何使用Python最新技术栈构建一个高效、稳定的中国版权登记数据爬虫系统。我们将使用Playwright+Asyncio实现无头浏览器自动化,结合Redis分布式任务队列和MongoDB数据存储,打造一个能够应对反爬机制的企业级数据采集方案。文章包含完整代码实现、性能优化技巧以及法律合规建议,帮助开发者快速掌握大规模数据采集的核心技术。本文详细介绍了2024年使用Python最新技术栈构建中国版权登记数据爬虫的完整方案。基于Playwright的无头浏览器自动化。

2201_76125261的博客 1897

AVFoundation 框架初探究(三)

转载自 http://www.cocoachina.com/ios/20180426/23191.html 这篇总结什么? 在该系列的上一篇的文章中,我们总结的大致内容如下: 1、视频录制  AVCaptureSession + AVCaptureMovieFileOutput 2、视频录制 AVCaptureSession + AVAssetWriter 3、AVCaptureSess...

qq_22220403的博客 786

学习QT之应用程序打包发布

一、编译QT程序(release编译) 二、将release文件夹中的可执行文件复制到一个空的文件夹中 三、使用windeployqt打包工程 切换到可执行文件路径,执行windeployqt xxx.exe: 然后就会将程序所需要用到的资源以及库文件生成到可执行文件路径下: 此时应用程序就可以点击运行了。 四、使用Enigma Virtual Box封包(将文件夹内的文件集成为单可执...

贝勒里恩的博客 762

AVFoundation Programming Guide - Playback

Playback 为了控制资源(assets)的播放(playback),我们可以使用AVPlayer 对象,在播放期间,我们能够使用AVPlayerItem实例来管理所播放资源的呈现状态,AVPlayerItemTrack 对象能够管理一个单独轨道(individual track)的呈现状态。为了显示视频,我们需要使用AVPlayerLayer 对象。 Pl

欢迎来到Jack的程序世界 2126

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

AVFoundation Programming Guide(官方文档翻译2)Using Assets - 使用Assets

Assets 可以来自文件或者媒体用户的iPod库、图片库。当你创建一个 asset 对象时,所有你可能想要检索该项目的信息不是立即可用的。一旦你有了一个电影 asset ,你可以从里面提取静态图像,转换到另一个格式,或者对内容就行修剪。

yofer张耀琦的专栏 2539

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

学习笔记- AVFoundation Programming Guide - Editing

Editing AVFoundation 提供了功能丰富的类方便编辑音视频assets。AVFoundation的编辑API的关键在于compositions。compositions简单的吧一个或多个不同媒体的assets集合到一起。 AVMutableComposition 类提供了插入和删除tracks的接口,以及管理他们的时间排序。 AVMutableAudioMix 类可以在com

sharpyl的专栏 782

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

如何使用AVFoundation框架

在Unity中调用iOS的AVFoundation框架以访问相机并获取图片,你需要编写iOS原生代码来利用AVFoundation的功能,然后将这些功能暴露给Unity。如果你确实需要使用AVFoundation或其他iOS原生功能,并希望与Unity紧密集成,你可能需要深入了解Unity的插件开发,以及iOS原生开发的相关知识。不过,由于这个过程相对复杂,通常建议直接使用Unity提供的插件或API来实现相机功能,除非有特定的需求必须使用AVFoundation。在这个类中,你将实现拍照的功能。

lcfengokok的博客 579

Unity---Assets路径下的资源文件夹打包AssetBundle

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System.Windows.Forms; using System; public class CreateAssetsBundle : EditorWi...

学海无涯 3159

ios使用AVFoundation读取二维码的方法

二维码(Quick Response Code,简称QR Code)是由水平和垂直两个方向上的线条设计而成的一种二维条形码(barcode)。可以编码网址、电话号码、文本等内容,能够存储大量的数据信息。自iOS 7以来,二维码的生成和读取只需要使用Core Image框架和AVFoundation框架就能轻松实现。在这里,我们主要介绍二维码的读取。关于二维码的生成,可以查看使用CIFilter生成...

zxtech_lxy的专栏 1465

AVFoundation开发秘籍笔记-03资源和元数据

一、资源AVAsset AVAsset是一个抽象类和不可变类,定义媒体资源混合呈现的方式,将媒体资源的静态属性模块化成为一个整体,比如标题、时长和元数据等。 AVAsset不需要考虑媒体资源所具有的两个重要范畴:1、提供了对基本媒体格式的层抽象,不需要关注具体格式,只关注资源这个概念。2、隐藏资源的位置信息。 AVAsset本身不是媒体资源,但他可以作为时基媒体的容器,由一个或多个带有描述自...

学习笔记 7万+

AVPlayer(二)AVAsset

https://www.sunyazhou.com/2017/06/16/Learning-AV-Foundation-AVAsset-Basic/?utm_source=tuicool&amp;utm_medium=referral AVAsset 专辑 一个抽象类,里面包含曲目、格式、时长, 以及元数据NSData(二进制的bytes). @property (nonatomic, r...

OdynO的专栏 5080

获取视频的某一帧

// 获取视频的某一帧 - (UIImage*) getVideoPreViewImageWithVideoPath:(NSURL *)videoPath { AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoPath options:nil]; AVAssetImageGenerator *gen = [[AVAss

YLGWHYH的专栏 2581

IOS音视频(三)AVFoundation 播放和录音

IOS音视频(三)AVFoundation静态图片拍摄

kyl282889543的博客 3322

iOS-----AVFoundation框架的功能详解

使用AVFoundation拍照和录制视频 需要开发自定义的拍照和录制视频功能,可借助于AVFoundation框架来实现,该框架提供了大量的类来完成拍照和录制视频.主要使用如下类: AVCaptureDevice:该对象代表物理输入设备,包括摄像头和麦克风.开发者可通过该对象来配置底层物理设备的属性.需要指出的是, 我们不能直接创建该类的实例,只能通过该类的devic...

weixin_30722589的博客 394

学习笔记- AVFoundation Programming Guide - Still and Video Media Capture

管理相机或麦克风等设备捕捉音视频,生成对象来表示输入输出,并且用 AVCaptureSession 对象来协调他们之间的数据流。需要用到下面几个类: . AVCaptureDevice 实例,表示输入设备。如:相机或麦克风; . AVCaptureInput 子类的实例,配置输入设备的端口; . AVCaptureOutput子类的实例,管理到视频文件或静态图的输出; . AVCaptur

sharpyl的专栏 1330
上一篇: 学习笔记- AVFoundation Programming Guide - 概括
下一篇: 学习笔记- AVFoundation Programming Guide - Playback
直隶码农
博客等级 码龄19年 95粉丝 103原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值