filigrane iPhone sur vidéo enregistrée.

dans mon Application je dois capturer une vidéo et mettre un filigrane sur cette vidéo. Le filigrane doit être un texte(temps et Notes). J'ai vu un code utilisant "QTKit". Cependant, j'ai lu que le cadre n'est pas disponible pour l'iPhone.

Merci D'avance.

16
demandé sur Dilip Rajkumar 2011-08-26 18:01:52

5 réponses

utiliser AVFoundation . Je suggère de saisir les cadres avec AVCaptureVideoDataOutput , puis de superposer le cadre capturé avec l'image en filigrane, et finalement d'écrire les cadres capturés et traités à un utilisateur de fichier AVAssetWriter .

recherche autour du débordement de la pile, il y a une tonne d'exemples fantastiques détaillant comment faire chacune de ces choses que j'ai mentionnées. Je n'en ai vu aucun qui donne des exemples de code pour exactement l'effet que vous souhaitez, mais vous devriez être en mesure de mélanger et match assez facilement.

EDIT:

regardez ces liens:

iPhone: AVCaptureSession capture output crashing (AVCaptureVideoDataOutput) - ce message pourrait être utile juste par la nature de contenir le code pertinent.

AVCaptureDataOutput retournera les images comme CMSampleBufferRef S. Convertissez-les en CGImageRef s en utilisant ce code:

    - (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;
}

De là, vous vous convertiriez en UIImage,

  UIImage *img = [UIImage imageWithCGImage:yourCGImage];  

puis utiliser

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

pour dessiner le cadre à un contexte, dessiner un PNG du filigrane dessus, puis Ajouter les images traitées à votre vidéo de sortie en utilisant AVAssetWriter . Je suggère de les ajouter en temps réel pour que vous ne remplissiez pas la mémoire de tonnes d'images.

comment exporter UIImage array comme film? - ce post montre comment ajouter les UIImages que vous avez traités à une vidéo pour une durée donnée.

cela devrait vous permettre de bien vous rendre au filigrane de vos vidéos. Rappelez-vous de pratiquer une bonne gestion de la mémoire, parce que la fuite des images qui arrivent à 20-30fps est un excellent moyen de planter l'application.

14
répondu James 2017-05-23 12:02:48

Ajouter un filigrane est plus simple. Vous avez juste besoin d'utiliser un CALayer et AVVideoCompositionCoreAnimationTool. Le code peut être copié et assemblé dans le même ordre. J'ai juste essayé d'insérer des commentaires dans entre pour une meilleure compréhension.

supposons que vous avez déjà enregistré la vidéo donc nous allons d'abord créer L'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]]; 

Avec ce code, vous serait en mesure d'exporter la vidéo, mais nous voulons pour ajouter la couche avec le filigrane d'abord. S'il vous plaît noter que certains codes peuvent sembler redondants, mais il est nécessaire que tout fonctionne.

nous créons D'abord le calque avec l'image en filigrane:

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 nous ne voulons pas d'image et que nous voulons du texte à la place:

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

le code suivant trie le calque dans l'ordre approprié:

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

maintenant nous créons la composition et ajoutons instructions pour insérer la couche:

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];

et maintenant nous sommes prêts à exporter:

_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];
42
répondu Julio Bailon 2012-01-10 02:43:33

déjà la réponse donnée par @Julio fonctionne bien en cas d'objectif-c Voici la même base de code pour Swift 3.0 :

WATERMARK & Generating SQUARE or CROPPED video like Instagram

obtenir le fichier de sortie à partir du répertoire de Documents & créer 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]

créer le calque avec l'image en filigrane:

    //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

créer le calque avec du texte en filigrane au lieu de l'image:

    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)

le code suivant trie la couche dans l'ordre approprié:

  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

ajouter les couches sur la vidéo dans l'ordre approprié pour le filigrane

  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

recadrer la vidéo en format carré 300*300 en taille

 //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))

Tourner à Portrait

//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]

dernière étape pour exporter la vidéo

        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
    }

ceci exportera la vidéo en taille carrée avec le filigrane comme texte ou Image

Merci

2
répondu Harjot Singh 2017-07-26 05:55:36

téléchargez simplement le code et utilisez-le.It is in Apple developer documentation Page.

http://developer.apple.com/library/ios/#samplecode/AVSimpleEditoriOS/Listings/AVSimpleEditor_AVSERotateCommand_m.html

1
répondu Babuli 2013-03-06 05:04:43

Voici l'exemple sur swift3 Comment insérer à la fois animé (tableau d'images/diapositives/cadres) et des filigranes d'image statique dans la vidéo enregistrée.

il utilise CAKeyframeAnimation pour animer les cadres, et il utilise AVMutableCompositionTrack , AVAssetExportSession et AVMutableVideoComposition avec Avmutablevideocomposition" pour tout combiner.

0
répondu Mikita Manko 2017-05-21 20:36:36