版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.08.17 |
前言
針對短視頻的上傳、編輯等功能有很多的SDK税手,比如騰訊的SDK、七牛的SDK等需纳,這里我就說一下我用過的美攝的SDK - 1.8.0芦倒,希望對大家有所幫助。感興趣的可以看我上面幾篇不翩。
1. 美攝SDK的使用(一)—— 產(chǎn)品介紹
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];
}
}
//監(jiān)聽
- (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
這個工具可以實現(xiàn)對短視頻進行特效編輯口蝠、背景音樂加載等功能器钟。
后記
未完,待續(xù)~~~