iOS : 裁剪视频中奇怪的绿线左侧和底部
iOS : Crop video weird green line left and bottom side in video
-如何去除视频上的绿线。
当裁剪视频 2 或 3 次时,在视频中显示绿色或混合绿红色闪烁线,视频左侧或底部或左侧和底部。
视频裁剪方法。
-(void)cropButton
{
CGRect cropFrame = self.cropView.croppedImageFrame;
//load our movie Asset
AVAsset *asset;
asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:[self.videoDataArr objectAtIndex:self.selectedIndex-1]]];
//create an avassetrack with our asset
AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
//create a video composition and preset some settings
AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1, 30);
//create a video instruction
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];
UIImageOrientation videoOrientation = [self getVideoOrientationFromAsset:asset];
CGAffineTransform t1 = CGAffineTransformIdentity;
CGAffineTransform t2 = CGAffineTransformIdentity;
switch (videoOrientation)
{
case UIImageOrientationUp:
t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height - cropFrame.origin.x, 0 - cropFrame.origin.y);
t2 = CGAffineTransformRotate(t1, M_PI_2);
break;
case UIImageOrientationDown:
t1 = CGAffineTransformMakeTranslation(0 - cropFrame.origin.x, clipVideoTrack.naturalSize.width - cropFrame.origin.y ); // not fixed width is the real height in upside down
t2 = CGAffineTransformRotate(t1, - M_PI_2);
break;
case UIImageOrientationRight:
t1 = CGAffineTransformMakeTranslation(0 - cropFrame.origin.x, 0 - cropFrame.origin.y);
t2 = CGAffineTransformRotate(t1, 0 );
break;
case UIImageOrientationLeft:
t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.width - cropFrame.origin.x, clipVideoTrack.naturalSize.height - cropFrame.origin.y );
t2 = CGAffineTransformRotate(t1, M_PI);
break;
default:
NSLog(@"no supported orientation has been found in this video");
break;
}
CGAffineTransform finalTransform = t2;
videoComposition.renderSize = CGSizeMake(cropFrame.size.width,cropFrame.size.height);
[transformer setTransform:finalTransform atTime:kCMTimeZero];
//add the transformer layer instructions, then add to video composition
instruction.layerInstructions = [NSArray arrayWithObject:transformer];
videoComposition.instructions = [NSArray arrayWithObject: instruction];
//Create an Export Path to store the cropped video
NSString * documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
__block NSString *exportPath = [documentsPath stringByAppendingFormat:@"/CroppedVideo.mp4"];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
//Remove any prevouis videos at that path
[[NSFileManager defaultManager] removeItemAtURL:exportUrl error:nil];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ;
exporter.videoComposition = videoComposition;
exporter.outputURL = exportUrl;
NSLog(@"exported url : %@",exportUrl);
exporter.outputFileType = AVFileTypeQuickTimeMovie;
[exporter exportAsynchronouslyWithCompletionHandler:^
{
dispatch_async(dispatch_get_main_queue(), ^{
switch ([exporter status]) {
case AVAssetExportSessionStatusCompleted:
{
self.navigationController.toolbarHidden = YES;
NSError *error = nil;
NSString *targetPath;
targetPath = [self.videoDataArr objectAtIndex:self.selectedIndex-1];
[FILEMANAGER removeItemAtPath:targetPath error:&error];
if(error)
{
NSLog(@"Error is : %@",error);
}
error = nil;
[FILEMANAGER moveItemAtPath:exportPath toPath:targetPath error:&error];
if(error)
{
NSLog(@"Error is : %@",error);
}
self.mySAVideoRangeSlider.videoUrl = self.videourl;
[self.mySAVideoRangeSlider getMovieFrame];
}
break;
}
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exporter error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
NSLog(@"NONE");
dispatch_async(dispatch_get_main_queue(), ^{
});
break;
}
});
}];
}
-视频裁剪后出现绿线,如何解决
您的视频渲染宽度应为偶数或可被 4 整除。
检查这个discussion link
Be aware. If you choose a resolution which is not divisible by 16, 8 or 4, you might end up with a 1px green border at either bottom or right side of your frame. I have seen this problem with
"If the horizontal or vertical size is not divisible by 16, then the encoder pads the image with a suitable number of black "overhang" samples at the right edge or bottom edge. These samples are discarded upon decoding. For example when coding HDTV at 1920x1080, an encoder appends 8 rows of black pixels to ht eimage array, to make the row count 1088."
-如何去除视频上的绿线。 当裁剪视频 2 或 3 次时,在视频中显示绿色或混合绿红色闪烁线,视频左侧或底部或左侧和底部。
视频裁剪方法。
-(void)cropButton
{
CGRect cropFrame = self.cropView.croppedImageFrame;
//load our movie Asset
AVAsset *asset;
asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:[self.videoDataArr objectAtIndex:self.selectedIndex-1]]];
//create an avassetrack with our asset
AVAssetTrack *clipVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
//create a video composition and preset some settings
AVMutableVideoComposition* videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1, 30);
//create a video instruction
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
AVMutableVideoCompositionLayerInstruction* transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];
UIImageOrientation videoOrientation = [self getVideoOrientationFromAsset:asset];
CGAffineTransform t1 = CGAffineTransformIdentity;
CGAffineTransform t2 = CGAffineTransformIdentity;
switch (videoOrientation)
{
case UIImageOrientationUp:
t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.height - cropFrame.origin.x, 0 - cropFrame.origin.y);
t2 = CGAffineTransformRotate(t1, M_PI_2);
break;
case UIImageOrientationDown:
t1 = CGAffineTransformMakeTranslation(0 - cropFrame.origin.x, clipVideoTrack.naturalSize.width - cropFrame.origin.y ); // not fixed width is the real height in upside down
t2 = CGAffineTransformRotate(t1, - M_PI_2);
break;
case UIImageOrientationRight:
t1 = CGAffineTransformMakeTranslation(0 - cropFrame.origin.x, 0 - cropFrame.origin.y);
t2 = CGAffineTransformRotate(t1, 0 );
break;
case UIImageOrientationLeft:
t1 = CGAffineTransformMakeTranslation(clipVideoTrack.naturalSize.width - cropFrame.origin.x, clipVideoTrack.naturalSize.height - cropFrame.origin.y );
t2 = CGAffineTransformRotate(t1, M_PI);
break;
default:
NSLog(@"no supported orientation has been found in this video");
break;
}
CGAffineTransform finalTransform = t2;
videoComposition.renderSize = CGSizeMake(cropFrame.size.width,cropFrame.size.height);
[transformer setTransform:finalTransform atTime:kCMTimeZero];
//add the transformer layer instructions, then add to video composition
instruction.layerInstructions = [NSArray arrayWithObject:transformer];
videoComposition.instructions = [NSArray arrayWithObject: instruction];
//Create an Export Path to store the cropped video
NSString * documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
__block NSString *exportPath = [documentsPath stringByAppendingFormat:@"/CroppedVideo.mp4"];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
//Remove any prevouis videos at that path
[[NSFileManager defaultManager] removeItemAtURL:exportUrl error:nil];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality] ;
exporter.videoComposition = videoComposition;
exporter.outputURL = exportUrl;
NSLog(@"exported url : %@",exportUrl);
exporter.outputFileType = AVFileTypeQuickTimeMovie;
[exporter exportAsynchronouslyWithCompletionHandler:^
{
dispatch_async(dispatch_get_main_queue(), ^{
switch ([exporter status]) {
case AVAssetExportSessionStatusCompleted:
{
self.navigationController.toolbarHidden = YES;
NSError *error = nil;
NSString *targetPath;
targetPath = [self.videoDataArr objectAtIndex:self.selectedIndex-1];
[FILEMANAGER removeItemAtPath:targetPath error:&error];
if(error)
{
NSLog(@"Error is : %@",error);
}
error = nil;
[FILEMANAGER moveItemAtPath:exportPath toPath:targetPath error:&error];
if(error)
{
NSLog(@"Error is : %@",error);
}
self.mySAVideoRangeSlider.videoUrl = self.videourl;
[self.mySAVideoRangeSlider getMovieFrame];
}
break;
}
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exporter error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
NSLog(@"NONE");
dispatch_async(dispatch_get_main_queue(), ^{
});
break;
}
});
}];
}
-视频裁剪后出现绿线,如何解决
您的视频渲染宽度应为偶数或可被 4 整除。
检查这个discussion link
Be aware. If you choose a resolution which is not divisible by 16, 8 or 4, you might end up with a 1px green border at either bottom or right side of your frame. I have seen this problem with
"If the horizontal or vertical size is not divisible by 16, then the encoder pads the image with a suitable number of black "overhang" samples at the right edge or bottom edge. These samples are discarded upon decoding. For example when coding HDTV at 1920x1080, an encoder appends 8 rows of black pixels to ht eimage array, to make the row count 1088."