iphone watermark video-watermarking

iPhone marca de agua en el video grabado.



watermark video-watermarking (5)

En mi aplicación, necesito capturar un video y poner una marca de agua en ese video. La marca de agua debe ser Texto (Tiempo y Notas). Vi un código usando el trabajo de marco "QTKit". Sin embargo, leí que el marco no está disponible para iPhone.

Gracias por adelantado.


Agregar una marca de agua es bastante más simple. Solo necesita usar CALayer y AVVideoCompositionCoreAnimationTool. El código solo puede ser copiado y ensamblado en el mismo orden. Acabo de intentar insertar algunos comentarios intermedios para una mejor comprensión.

Asumamos que ya grabó el video, así que primero vamos a crear el AVURLAsset:

AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:outputFileURL options:nil]; AVMutableComposition* mixComposition = [AVMutableComposition composition]; AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; AVAssetTrack *clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:clipVideoTrack atTime:kCMTimeZero error:nil]; [compositionVideoTrack setPreferredTransform:[[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];

Con solo este código podrá exportar el video, pero primero queremos agregar la capa con la marca de agua. Tenga en cuenta que algunos códigos pueden parecer redundantes, pero es necesario para que todo funcione.

Primero creamos la capa con la imagen de marca de agua:

UIImage *myImage = [UIImage imageNamed:@"icon.png"]; CALayer *aLayer = [CALayer layer]; aLayer.contents = (id)myImage.CGImage; aLayer.frame = CGRectMake(5, 25, 57, 57); //Needed for proper display. We are using the app icon (57x57). If you use 0,0 you will not see it aLayer.opacity = 0.65; //Feel free to alter the alpha here

Si no queremos una imagen y queremos un texto en su lugar:

CATextLayer *titleLayer = [CATextLayer layer]; titleLayer.string = @"Text goes here"; titleLayer.font = @"Helvetica"; titleLayer.fontSize = videoSize.height / 6; //?? titleLayer.shadowOpacity = 0.5; titleLayer.alignmentMode = kCAAlignmentCenter; titleLayer.bounds = CGRectMake(0, 0, videoSize.width, videoSize.height / 6); //You may need to adjust this for proper display

El siguiente código ordena la capa en el orden correcto:

CGSize videoSize = [videoAsset naturalSize]; CALayer *parentLayer = [CALayer layer]; CALayer *videoLayer = [CALayer layer]; parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height); videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height); [parentLayer addSublayer:videoLayer]; [parentLayer addSublayer:aLayer]; [parentLayer addSublayer:titleLayer]; //ONLY IF WE ADDED TEXT

Ahora estamos creando la composición y agregamos las instrucciones para insertar la capa:

AVMutableVideoComposition* videoComp = [[AVMutableVideoComposition videoComposition] retain]; videoComp.renderSize = videoSize; videoComp.frameDuration = CMTimeMake(1, 30); videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer]; /// instruction AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]); AVAssetTrack *videoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction]; videoComp.instructions = [NSArray arrayWithObject: instruction];

Y ahora estamos listos para exportar:

_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];//AVAssetExportPresetPassthrough _assetExport.videoComposition = videoComp; NSString* videoName = @"mynewwatermarkedvideo.mov"; NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName]; NSURL *exportUrl = [NSURL fileURLWithPath:exportPath]; if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) { [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil]; } _assetExport.outputFileType = AVFileTypeQuickTimeMovie; _assetExport.outputURL = exportUrl; _assetExport.shouldOptimizeForNetworkUse = YES; [strRecordedFilename setString: exportPath]; [_assetExport exportAsynchronouslyWithCompletionHandler: ^(void ) { [_assetExport release]; //YOUR FINALIZATION CODE HERE } ]; [audioAsset release]; [videoAsset release];


Este es el ejemplo de swift3 sobre cómo insertar marcas de agua de imágenes animadas (matriz de imágenes / diapositivas / marcos) y estáticas en el video grabado.

Utiliza CAKeyframeAnimation para animar los marcos, y usa AVMutableCompositionTrack , AVAssetExportSession y AVMutableVideoComposition junto con AVMutableVideoCompositionInstruction para combinar todo junto.



Ya la respuesta dada por @Julio funciona bien en el caso del objetivo-c. Aquí está la misma base de código para Swift 3.0 :

WATERMARK y generación de video CUADRADO o RECORTADO como Instagram

Obtención del archivo de salida del Directorio de documentos y creación de AVURLAsset

//output file let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first let outputPath = documentsURL?.appendingPathComponent("squareVideo.mov") if FileManager.default.fileExists(atPath: (outputPath?.path)!) { do { try FileManager.default.removeItem(atPath: (outputPath?.path)!) } catch { print ("Error deleting file") } } //input file let asset = AVAsset.init(url: filePath) print (asset) let composition = AVMutableComposition.init() composition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid) //input clip let clipVideoTrack = asset.tracks(withMediaType: AVMediaTypeVideo)[0]

Crea la capa con la imagen de marca de agua:

//adding the image layer let imglogo = UIImage(named: "video_button") let watermarkLayer = CALayer() watermarkLayer.contents = imglogo?.cgImage watermarkLayer.frame = CGRect(x: 5, y: 25 ,width: 57, height: 57) watermarkLayer.opacity = 0.85

Crea la capa con texto como marca de agua en lugar de imagen:

let textLayer = CATextLayer() textLayer.string = "Nodat" textLayer.foregroundColor = UIColor.red.cgColor textLayer.font = UIFont.systemFont(ofSize: 50) textLayer.alignmentMode = kCAAlignmentCenter textLayer.bounds = CGRect(x: 5, y: 25, width: 100, height: 20)

El siguiente código ordena la capa en el orden correcto:

let videoSize = clipVideoTrack.naturalSize let parentlayer = CALayer() let videoLayer = CALayer() parentlayer.frame = CGRect(x: 0, y: 0, width: videoSize.height, height: videoSize.height) videoLayer.frame = CGRect(x: 0, y: 0, width: videoSize.height, height: videoSize.height) parentlayer.addSublayer(videoLayer) parentlayer.addSublayer(watermarkLayer) parentlayer.addSublayer(textLayer) //for text layer only

Agregar las capas sobre el video en el orden correcto para la marca de agua

let videoSize = clipVideoTrack.naturalSize let parentlayer = CALayer() let videoLayer = CALayer() parentlayer.frame = CGRect(x: 0, y: 0, width: videoSize.height, height: videoSize.height) videoLayer.frame = CGRect(x: 0, y: 0, width: videoSize.height, height: videoSize.height) parentlayer.addSublayer(videoLayer) parentlayer.addSublayer(watermarkLayer) parentlayer.addSublayer(textLayer) //for text layer only

Recorte del video en formato cuadrado - de 300 * 300 en tamaño

//make it square let videoComposition = AVMutableVideoComposition() videoComposition.renderSize = CGSize(width: 300, height: 300) //change it as per your needs. videoComposition.frameDuration = CMTimeMake(1, 30) videoComposition.renderScale = 1.0 //Magic line for adding watermark to the video videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayers: [videoLayer], in: parentlayer) let instruction = AVMutableVideoCompositionInstruction() instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30))

Girar a retrato

//rotate to potrait let transformer = AVMutableVideoCompositionLayerInstruction(assetTrack: clipVideoTrack) let t1 = CGAffineTransform(translationX: clipVideoTrack.naturalSize.height, y: -(clipVideoTrack.naturalSize.width - clipVideoTrack.naturalSize.height) / 2) let t2: CGAffineTransform = t1.rotated(by: .pi/2) let finalTransform: CGAffineTransform = t2 transformer.setTransform(finalTransform, at: kCMTimeZero) instruction.layerInstructions = [transformer] videoComposition.instructions = [instruction]

Paso final para exportar el video.

let exporter = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetMediumQuality) exporter?.outputFileType = AVFileTypeQuickTimeMovie exporter?.outputURL = outputPath exporter?.videoComposition = videoComposition exporter?.exportAsynchronously() { handler -> Void in if exporter?.status == .completed { print("Export complete") DispatchQueue.main.async(execute: { completion(outputPath) }) return } else if exporter?.status == .failed { print("Export failed - /(String(describing: exporter?.error))") } completion(nil) return }

Esto exportará el video en tamaño cuadrado con marca de agua como texto o imagen

Gracias


Utilice AVFoundation . Yo sugeriría capturar fotogramas con AVCaptureVideoDataOutput , luego superponer el fotograma capturado con la imagen de marca de agua y, finalmente, escribir los fotogramas capturados y procesados ​​en un usuario de archivos AVAssetWriter .

Busque alrededor del desbordamiento de pila, hay un montón de ejemplos fantásticos que detallan cómo hacer cada una de estas cosas que he mencionado. No he visto ninguno que proporcione ejemplos de código para el efecto exacto que desea, pero debería poder mezclar y combinar con bastante facilidad.

EDITAR:

Echa un vistazo a estos enlaces:

iPhone: Falla de salida de captura de AVCaptureSession (AVCaptureVideoDataOutput) : esta publicación puede ser útil simplemente por la naturaleza de que contiene código relevante.

AVCaptureDataOutput devolverá imágenes como CMSampleBufferRef s. Conviértalos a CGImageRef s usando este código:

- (CGImageRef) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer // Create a CGImageRef from sample buffer data { CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); CVPixelBufferLockBaseAddress(imageBuffer,0); // Lock the image buffer uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); // Get information of the image size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); size_t width = CVPixelBufferGetWidth(imageBuffer); size_t height = CVPixelBufferGetHeight(imageBuffer); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); CGImageRef newImage = CGBitmapContextCreateImage(newContext); CGContextRelease(newContext); CGColorSpaceRelease(colorSpace); CVPixelBufferUnlockBaseAddress(imageBuffer,0); /* CVBufferRelease(imageBuffer); */ // do not call this! return newImage; }

Desde allí se convertiría a un UIImage,

UIImage *img = [UIImage imageWithCGImage:yourCGImage];

Entonces use

[img drawInRect:CGRectMake(x,y,height,width)];

para dibujar el marco a un contexto, dibuje un PNG de la marca de agua sobre él y luego agregue las imágenes procesadas a su salida de video usando AVAssetWriter . Sugeriría agregarlos en tiempo real para que no esté llenando la memoria con toneladas de UIImages.

¿Cómo exporto UIImage array como una película? - esta publicación muestra cómo agregar los UIImages que ha procesado a un video para una duración determinada.

Esto debería ponerte en camino para filmar tus videos. Recuerde practicar una buena gestión de la memoria, ya que las imágenes con fugas que llegan a 20-30 fps son una excelente manera de bloquear la aplicación.