版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.08.17 |
前言
针对短视频的上传、编辑等功能有很多的SDK,比如腾讯的SDK、七牛的SDK等,这里我就说一下我用过的美摄的SDK - 1.8.0,希望对大家有所帮助。感兴趣的可以看我上面几篇。
1. 美摄SDK的使用(一)—— 产品介绍
2. 美摄SDK的使用(二)—— 框架介绍
3. 美摄SDK的使用(三)—— 短视频的录制工具类的封装
短视频编辑工具类的封装
下面我就封装了一下短视频编辑的工具。
1. JJShortVideoEditManager.h
@class NvsStreamingContext;
@class NvsLiveWindow;
@class NvsTimeline;
@class JJEditVideoModel;
@protocol JJShortVideoEditDelegate <NSObject>
- (void)beginLoadShortVideo:(NSString *)path;
- (void)loadLoaderProcess:(NSInteger)process;
- (void)shortVideoUploadFaile;
- (void)saveToLibrary;
- (void)didPlaybackEOF:(NvsTimeline *)timeline;
- (void)didPlaySuccess;
@end
@interface JJShortVideoEditManager : NSObject
@property (nonatomic, weak) id<JJShortVideoEditDelegate>delegate;
@property (nonatomic, assign) int type;
- (void)loadPreView:(NvsLiveWindow *)preview;
//取得默认封面
- (UIImage *)selectDefaletCoverImage;
//加载短视频
- (void)loadVideoPath:(NSMutableArray <JJEditVideoModel *>*)videoArray;
- (NvsStreamingContext *)context;
- (NvsTimeline *)timeLine;
- (void)loadPlay;
- (void)saveShortVideo:(NSString *)path;
- (NSArray *)loadStickerArray;
- (NSArray *)loadFxArray;
- (void)addStickerForShortVideo:(NSInteger)index;
- (void)addFxForShortVideo:(NSInteger)index;
- (void)clearCache;
- (void)stopPlay;
@end
2.JJShortVideoEditManager.m
#import "JJShortVideoEditManager.h"
#import "NvsStreamingContext.h"
#import "NvsVideoTrack.h"
#import "NvsTimeline.h"
#import "JJEditVideoModel.h"
#import "NvsVideoClip.h"
#import "NvsFxDescription.h"
@interface JJShortVideoEditManager () <NvsStreamingContextDelegate>
@property (nonatomic, strong) NvsStreamingContext *context;
@property (nonatomic, strong) NvsTimeline *timeLine;
@property (nonatomic, strong) NvsVideoTrack *videoTrack;
@property (nonatomic, strong) NvsLiveWindow *preView;
@property (nonatomic, strong) NSArray <JJEditVideoModel *>*videoArray;
@property (nonatomic, copy) NSString *path;
@property (nonatomic, copy) NSMutableString *stickerPackageId;
@property (nonatomic, copy) NSMutableString *videoFxPackageId;
@property (nonatomic, strong) NSArray *lstVideoFx;
@property (nonatomic, strong) NSArray *lstVideoTransition;
@property (nonatomic, assign) BOOL isSave;
@property (nonatomic, assign) BOOL hasAddedSticker;
@end
@implementation JJShortVideoEditManager
#pragma mark - Override Base Function
- (void)dealloc
{
DDLogWarn(@"%@ 已释放", self);
}
#pragma mark - Object Public Function
//加载预览视图
- (void)loadPreView:(NvsLiveWindow *)preview
{
_preView = preview;
}
//加载短视频
- (void)loadVideoPath:(NSArray <JJEditVideoModel *>*)videoArray
{
_videoArray = videoArray;
}
//时间线
- (NvsTimeline *)timeLine
{
if (!_timeLine) {
if (!_timeLine) {
NvsVideoResolution videoEditRes;
videoEditRes.imageWidth = 720/2;
videoEditRes.imageHeight = 1280/2;
videoEditRes.imagePAR = (NvsRational){1, 1};
NvsRational videoFps = {25, 1};
NvsAudioResolution audioEditRes;
audioEditRes.sampleRate = 48000;
audioEditRes.channelCount = 2;
audioEditRes.sampleFormat = NvsAudSmpFmt_S16;
NvsTimeline *timeLine = [self.context createTimeline:&videoEditRes videoFps:&videoFps audioEditRes:&audioEditRes];
_timeLine = timeLine;
_videoTrack = [timeLine appendVideoTrack];
for (JJEditVideoModel *model in self.videoArray) {
[_videoTrack appendClip:model.path];
}
}
if (!self.context.delegate) {
self.context.delegate = self;
}
[self.context connectTimeline:_timeLine withLiveWindow:self.preView];
}
if (!self.context.delegate) {
self.context.delegate = self;
[self.context connectTimeline:self.timeLine withLiveWindow:self.preView];
}
return _timeLine;
}
//播放
- (void)loadPlay
{
self.context.delegate = self;
[self.context connectTimeline:self.timeLine withLiveWindow:self.preView];
if ([self.context playbackTimeline:self.timeLine startTime:0 endTime:self.timeLine.duration videoSizeMode:NvsVideoPreviewSizeModeLiveWindowSize preload:YES flags:0]) {
NSLog(@"播放成功");
}
// [self.context playbackTimeline:self.timeLine startTime:0 endTime:self.timeLine.duration videoSizeMode:NvsVideoPreviewSizeModeLiveWindowSize preload:YES flags:0];
}
- (void)saveShortVideo:(NSString *)path
{
if (self.context.delegate == nil) {
self.context.delegate = self;
}
_path = path;
NvsCompileVideoResolutionGrade grade;
if (ZebraUIDevice_iphone5 || ZebraUIDevice_iphone4 || ZebraUIDevice_iphone4S) {
grade = NvsCompileVideoResolutionGrade480;
}
else if (ZebraUIDevice_iphone5S || ZebraUIDevice_iphone5C){
grade = NvsCompileVideoResolutionGrade720;
}
else {
grade = NvsCompileVideoResolutionGrade1080;
}
if ([self.context compileTimeline:self.timeLine startTime:0 endTime:self.timeLine.duration outputFilePath:path videoResolutionGrade:grade videoBitrateGrade:NvsCompileBitrateGradeHigh flags:0]) {
}
else {
NSLog(@"上传失败,请重试");
if (_type == 1) {
if ([self.delegate respondsToSelector:@selector(shortVideoUploadFaile)]) {
[self.delegate shortVideoUploadFaile];
}
}
}
}
//贴纸
- (void)addStickerForShortVideo:(NSInteger)index
{
if (_hasAddedSticker) {
NvsTimelineAnimatedSticker *sticker = [self.timeLine getFirstAnimatedSticker];
while (sticker)
sticker = [self.timeLine removeAnimatedSticker:sticker];
_hasAddedSticker = NO;
}
else {
if ([_stickerPackageId isEqualToString:@""])
return;
for (unsigned int i = 0; i < _videoTrack.clipCount; i++) {
NvsVideoClip *videoClip = [_videoTrack getClipWithIndex:i];
[videoClip setPan:0 andScan:1];
[self.timeLine addAnimatedSticker:videoClip.inPoint duration:videoClip.outPoint - videoClip.inPoint animatedStickerPackageId:_stickerPackageId];
}
_hasAddedSticker = YES;
}
[self loadPlay];
}
- (void)addFxForShortVideo:(NSInteger)index
{
if (_videoTrack.clipCount <= 0)
return;
if (index > 0) {
NSString *fxName = [_lstVideoFx objectAtIndex:index];
if ([fxName isEqualToString:@"Beauty"]) {
NvsFxDescription *fxDescription = [_context getVideoFxDescription:fxName];
NSArray *paramsInfo = [fxDescription getAllParamsInfo];
for (unsigned int i = 0; i < _videoTrack.clipCount; i++) {
NvsVideoClip *videoClip = [_videoTrack getClipWithIndex:i];
[videoClip removeAllFx];
[videoClip appendBeautyFx];
}
}
else {
if ([fxName isEqualToString:@"None"]) {
for (unsigned int i = 0; i < _videoTrack.clipCount; i++)
[[_videoTrack getClipWithIndex:i] removeAllFx];
} else if ([fxName isEqualToString:@"Package1"]) {
for (unsigned int i = 0; i < _videoTrack.clipCount; i++) {
NvsVideoClip *videoClip = [_videoTrack getClipWithIndex:i];
[videoClip removeAllFx];
[videoClip appendPackagedFx:_videoFxPackageId];
}
} else {
for (unsigned int i = 0; i < _videoTrack.clipCount; i++) {
NvsVideoClip *videoClip = [_videoTrack getClipWithIndex:i];
[videoClip removeAllFx];
[videoClip appendBuiltinFx:fxName];
}
}
}
}
else {
NSString *transName = [_lstVideoTransition objectAtIndex:index];
if ([transName isEqualToString:@"None"])
transName = @"";
for (unsigned int i = 0; i < _videoTrack.clipCount - 1; i++)
[_videoTrack setBuiltinTransition:i withName:transName];
}
[self loadPlay];
}
- (void)stopPlay
{
[self.context stop];
}
- (void)clearCache
{
[self.context stop];
[self.context clearCachedResources:YES];
self.context.delegate = nil;
}
- (UIImage *)selectDefaletCoverImage
{
int64_t timeInterval = 1000*500;
UIImage *image = [self.context grabImageFromTimeline:self.timeLine timestamp:timeInterval proxyScale:nil];
return image;
}
- (NSArray *)loadStickerArray
{
_stickerPackageId = [[NSMutableString alloc] initWithString:@""];
NSString *sitckerFilePath = [[[NSBundle mainBundle]bundlePath ]stringByAppendingPathComponent:@"89740AEA-80D6-432A-B6DE-E7F6539C4121.animatedsticker"];
if (![[NSFileManager defaultManager] fileExistsAtPath:sitckerFilePath]) {
DDLogError(@"Sticker package file is not exist!");
} else {
NvsAssetPackageManagerError error = [self.context.assetPackageManager installAssetPackage:sitckerFilePath license:nil type:NvsAssetPackageType_AnimatedSticker sync:YES assetPackageId:_stickerPackageId];
if (error != NvsAssetPackageManagerError_NoError && error != NvsAssetPackageManagerError_AlreadyInstalled) {
DDLogError(@"Failed to install sticker package!");
}
}
return @[@"贴纸"];
}
- (NSArray *)loadFxArray
{
_videoFxPackageId = [[NSMutableString alloc] initWithString:@""];
bool package1Valid = true;
NSString *appPath =[[NSBundle mainBundle] bundlePath];
NSString *package1Path = [appPath stringByAppendingPathComponent:@"7FFCF99A-5336-4464-BACD-9D32D5D2DC5E.videofx"];
if (![[NSFileManager defaultManager] fileExistsAtPath:package1Path]) {
DDLogError(@"Video fx package file is not exist!");
package1Valid = false;
} else {
NvsAssetPackageManagerError error = [_context.assetPackageManager installAssetPackage:package1Path license:nil type:NvsAssetPackageType_VideoFx sync:YES assetPackageId:_videoFxPackageId];
if (error != NvsAssetPackageManagerError_NoError && error != NvsAssetPackageManagerError_AlreadyInstalled) {
DDLogError(@"Failed to install video fx package!");
package1Valid = false;
}
}
NSMutableArray *lstVideoFx = [NSMutableArray arrayWithObject:@"None"];
[lstVideoFx addObject:@"Beauty"];
[lstVideoFx addObjectsFromArray:[_context getAllBuiltinVideoFxNames]];
if (package1Valid)
[lstVideoFx addObject:@"Package1"];
_lstVideoFx = lstVideoFx.copy;
NSMutableArray *lstVideoTransition = [NSMutableArray arrayWithObject:@"None"];
[lstVideoTransition addObjectsFromArray:[self.context getAllBuiltinVideoTransitionNames]];
_lstVideoTransition = lstVideoFx.copy;
return _lstVideoFx.copy;
}
#pragma mark - Object Private Function
- (void)beginLoadShortVideo:(NSString *)path
{
if ([self.delegate respondsToSelector:@selector(beginLoadShortVideo:)]) {
[self.delegate beginLoadShortVideo:path];
}
}
- (void)saveToLibrary
{
if ([self.delegate respondsToSelector:@selector(saveToLibrary)]) {
[self.delegate saveToLibrary];
}
}
- (void)loadLoaderProcess:(NSInteger)process
{
if ([self.delegate respondsToSelector:@selector(loadLoaderProcess:)]) {
[self.delegate loadLoaderProcess:process];
}
}
//监听
- (void)didPlaybackEOF:(NvsTimeline *)timeline
{
if ([self.delegate respondsToSelector:@selector(didPlaybackEOF:)]) {
[self.delegate didPlaybackEOF:timeline];
}
}
#pragma mark - Lazy Load
- (NvsStreamingContext *)context
{
if (!_context) {
_context = [NvsStreamingContext sharedInstance];
_context.delegate = self;
}
return _context;
}
#pragma mark - NvsStreamingContextDelegate
- (void)didPlaybackStopped:(NvsTimeline *)timeline
{
if ([self.delegate respondsToSelector:@selector(didPlaybackEOF:)]) {
[self.delegate didPlaybackEOF:timeline];
}
}
- (void)didStreamingEngineStateChanged:(NvsStreamingEngineState)state
{
if (state == NvsStreamingEngineState_CapturePreview) {
if ([self.delegate respondsToSelector:@selector(didPlaybackEOF:)]) {
[self.delegate didPlaybackEOF:_timeLine];
}
}
}
- (void)didFirstVideoFramePresented:(NvsTimeline *)timeline
{
if ([self.delegate respondsToSelector:@selector(didPlaySuccess)]) {
[self.delegate didPlaySuccess];
}
}
- (void)didCompileProgress:(NvsTimeline *)timeline progress:(int)progress
{
NSLog(@"process : %d", progress);
if (_type == 1) {
[self loadLoaderProcess:progress/2];
}
}
- (void)didCompileFailed:(NvsTimeline *)timeline
{
NSLog(@"生成失败");
if ([self.delegate respondsToSelector:@selector(shortVideoUploadFaile)]) {
[self.delegate shortVideoUploadFaile];
}
}
- (void)didCompileFinished:(NvsTimeline *)timeline
{
NSLog(@"生成成功");
if (_type == 1) {
[self beginLoadShortVideo:_path];
}
else {
if (_isSave) {
return;
}
if ([self.delegate respondsToSelector:@selector(saveToLibrary)]) {
_isSave = YES;
[self.delegate saveToLibrary];
}
}
}
@end
这个工具可以实现对短视频进行特效编辑、背景音乐加载等功能。
后记
未完,待续~~~