iOS视频添加水印两种方式(不用到第三方框架)
iOS视频添加水印两种方式(不用到第三方框架)
1、视频加水印,并保存到沙盒当中
//原视频sureasset,有外界传进来
AVURLAsset *asset = (AVURLAsset *)[self addPhotoTitleWithAsset:sureasset][0];
AVMutableVideoComposition *mainCompositionInst = [self addPhotoTitleWithAsset:sureasset][1];
sureasset = asset;
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset: sureasset presetName:AVAssetExportPresetMediumQuality];
NSString *failPath = [self getVideosPath:@"localVideo"];//获取路径
NSURL *filUrl = [NSURL fileURLWithPath:failPath];
session.outputURL = filUrl;//视频输出地址
session.outputFileType = AVFileTypeMPEG4;//AVFileTypeQuickTimeMovie;//AVFileTypeMPEG4;
// 这个一般设置为yes(指示输出文件应针对网络使用进行优化,例如QuickTime电影文件应支持“快速启动”)
session.shouldOptimizeForNetworkUse = YES;
// 文件的最大多大的设置
session.fileLengthLimit = 30 * 1024 * 1024;
session.shouldOptimizeForNetworkUse = YES;
session.videoComposition = mainCompositionInst;
[session exportAsynchronouslyWithCompletionHandler:^(void){
dispatch_async(dispatch_get_main_queue(), ^{
//视频导入成功
//failPath为本地视频地址
completeBlock(failPath,YES);
});
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//获取路径
- (NSString *)getVideosPath:(NSString *)videoName{
NSString *documents = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
documents = [documents stringByAppendingPathComponent:@"CCTV5"];
documents = [self action_addFiles:documents];//判断文件是否存在
NSString *failPath = [documents stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4",videoName]];
return failPath;
}
1
2
3
4
5
6
7
8
#pragma mark- 视频加水印
//添加水印
-(NSArray *)addPhotoTitleWithAsset:(AVAsset *)videoAsset
{
//1 创建AVAsset实例
//AVURLAsset*videoAsset = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:path]];
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
//3 视频通道
AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject]
atTime:kCMTimeZero error:nil];
//2 音频通道
AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeAudio] firstObject]
atTime:kCMTimeZero error:nil];
//3.1 AVMutableVideoCompositionInstruction 视频轨道中的一个视频,可以缩放、旋转等
AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration);
// 3.2 AVMutableVideoCompositionLayerInstruction 一个视频轨道,包含了这个轨道上的所有视频素材
AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[videolayerInstruction setOpacity:0.0 atTime:videoAsset.duration];
// 3.3 - Add instructions
mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil];
//AVMutableVideoComposition:管理所有视频轨道,水印添加就在这上面
AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
CGSize naturalSize = videoAssetTrack.naturalSize;
//防崩溃处理,这个width可能为空,按比例给他值
if (naturalSize.width == 0) {
CGFloat a = (1280.f / 720);
naturalSize.width = a * naturalSize.height;
}
float renderWidth, renderHeight;
renderWidth = naturalSize.width;
renderHeight = naturalSize.height;
mainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight);
mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1, 30);
[self applyVideoEffectsToComposition:mainCompositionInst size:naturalSize];
NSArray *arrar = [NSArray arrayWithObjects:mixComposition,mainCompositionInst, nil];
return arrar;;
}
/**
设置水印及其对应视频的位置
@param composition 视频的结构
@param size 视频的尺寸
*/
- (void)applyVideoEffectsToComposition:(AVMutableVideoComposition *)composition size:(CGSize)size
{
// 文字
CATextLayer *subtitle1Text = [[CATextLayer alloc] init];
// [subtitle1Text setFont:@"Helvetica-Bold"];
[subtitle1Text setFontSize:36];
[subtitle1Text setFrame:CGRectMake(10, size.height-10-230, size.width, 100)];
[subtitle1Text setString:@"央视体育5 水印"];
// [subtitle1Text setAlignmentMode:kCAAlignmentCenter];
[subtitle1Text setForegroundColor:[[UIColor whiteColor] CGColor]];
//图片
CALayer*picLayer = [CALayer layer];
//picLayer.contents = (id)[UIImage imageNamed:@"CTVITTRIMSource.bundle/QQ"].CGImage; //本地图片
picLayer.contents = (id)self.videoWaterMarkImage.CGImage; //本地图片2
//NSString *imageUrl = @"http://p1.img.cctvpic.com/photoAlbum/templet/special/PAGEQ1KSin2j2U5FERGWHp1h160415/ELMTnGlKHUJZi7lz19PEnqhM160415_1460715755.png";
//picLayer.contents = (id)[self getImageFromURL:imageUrl].CGImage; //远程图片
CGFloat width = 63;
CGFloat leftMargin = 16 * [self scaleSizeWithHeight:size.height];
CGFloat topMargin = 20 * [self scaleSizeWithHeight:size.height];
if (self.videoWaterMarkPlace == WaterMarkTopLeft) {
picLayer.frame = CGRectMake(leftMargin, size.height-topMargin-[self scaleSizeWithHeight:size.height]*50, [self scaleSizeWithHeight:size.height]*width, [self scaleSizeWithHeight:size.height]*width);
}
if (self.videoWaterMarkPlace == WaterMarkBottomLeft) {
picLayer.frame = CGRectMake(leftMargin, 20, [self scaleSizeWithHeight:size.height]*50, [self scaleSizeWithHeight:size.height]*50);
}
if (self.videoWaterMarkPlace == WaterMarkTopRight) {
picLayer.frame = CGRectMake(size.width - 20 - [self scaleSizeWithHeight:size.height]*50, size.height-20-[self scaleSizeWithHeight:size.height]*50, [self scaleSizeWithHeight:size.height]*50, [self scaleSizeWithHeight:size.height]*50);
}
if (self.videoWaterMarkPlace == WaterMarkBottomRight) {
picLayer.frame = CGRectMake(size.width - 20 - [self scaleSizeWithHeight:size.height]*50, 20, [self scaleSizeWithHeight:size.height]*50, [self scaleSizeWithHeight:size.height]*50);
}
// 2 - The usual overlay
CALayer *overlayLayer = [CALayer layer];
[overlayLayer addSublayer:picLayer];
// [overlayLayer addSublayer:subtitle1Text];
overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
[overlayLayer setMasksToBounds:YES];
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
videoLayer.frame = CGRectMake(0, 0, size.width, size.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:overlayLayer];
composition.animationTool = [AVVideoCompositionCoreAnimationTool
videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
}
//ios 从网络上获取图片
-(UIImage *) getImageFromURL:(NSString *)fileURL {
//https://vod.cctv.cn/cctvsports/cctv5/img/advertisingImage.jpg
NSLog(@"执行图片下载函数");
UIImage * result;
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:fileURL]];
result = [UIImage imageWithData:data];
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
2、另一种实现方式
// [self applyVideoEffectsToComposition:mainCompositionInst size:naturalSize];
CIFilter *watermarkFilter = [CIFilter filterWithName:@"CISourceOverCompositing"];
mainCompositionInst = [AVMutableVideoComposition videoCompositionWithAsset:videoAsset applyingCIFiltersWithHandler:^(AVAsynchronousCIImageFilteringRequest * _Nonnull request) {
CIImage *watermarkImage = [[CIImage alloc] initWithCGImage:self.videoWaterMarkImage.CGImage];
CIImage *source = request.sourceImage;
[watermarkFilter setValue:source forKey:kCIInputBackgroundImageKey];
[watermarkFilter setValue:[watermarkImage imageByApplyingTransform:CGAffineTransformMakeScale(0.5, 0.5)] forKey:kCIInputImageKey];
[watermarkFilter setValue:[watermarkImage imageByApplyingTransform:CGAffineTransformMakeTranslation(14, source.extent.size.height - 14 - watermarkImage.extent.size.height)] forKey:kCIInputImageKey];
[request finishWithImage:watermarkFilter.outputImage context:nil];
}];
// // // 4 - 输出路径
————————————————
版权声明:本文为CSDN博主「黑码哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liyunxiangrxm/article/details/106687545