QTKit - 合并两个不同宽度和高度的视频? [英] QTKit - Merge two videos with different width and height?

查看:205
本文介绍了QTKit - 合并两个不同宽度和高度的视频?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



这里是问题:

strong>



我刚刚发现,如果我尝试合并两个不同宽度& height输出是一个视频,其高度和宽度与大视频相同,但包含一个黑色和宽边框的小视频。



问题: strong>



如何将两个视频合并在一起并获得具有正确格式(宽度/高度)的输出视频?



要更好地了解我需要的示例:



我有两个视频:



视频1 = 1920 x 1280
VIdeo 2 = 1280 x 960



我想要的:1920 x 1280的视频(需要上传 -

 

code> - (void)voidMethodToCombine {


NSError * err = nil;
QTMovie * myCombinedMovie = [[QTMovie alloc] initToWritableData:[NSMutableData data] error:& err];
if(err)
{
NSRunAlertPanel(@Errore nella creazione del video,[err localizedDescription],nil,@Chiudi,nil,nil);
return;
return;
}


//创建文件打开对话框类。
NSSavePanel * savePanel = [NSSavePanel savePanel]; // Dove salvo il video?


if([savePanel runModal])// Se premo ok
{
[indicatore setUsesThreadedAnimation:YES];
[indicatore startAnimation:self];
NSURL * saveURL = savePanel.URL;
NSString * savePath = [saveURL path];
// Prelevo i 2 percorsi e gli inserisco negli array

NSString * video1 = [URLVideo1 stringValue];
NSString * video2 = [URLVideo2 stringValue];

NSURL * theURLvideo1 = [NSURL fileURLWithPath:video1];

NSURL * theURLvideo2 = [NSURL fileURLWithPath:video2];

if((theURLvideo1)&(theURLvideo2)){



NSArray * myMovieURLs = [NSArray arrayWithObjects:theURLvideo1,theURLvideo2,零];

for(NSURL * url in myMovieURLs)
{
QTMovie * theMovie = [QTMovie movieWithURL:url error:& err];
if(err){
NSRunAlertPanel(@Errore durante il caricamento di uno dei film,[err localizedDescription],nil,@Chiudi,nil,nil);
return;
}
QTTimeRange timeRange = QTMakeTimeRange(QTZeroTime,[theMovie duration]);
QTTime insertionTime = [myCombinedMovie duration];
[myCombinedMovie insertSegmentOfMovie:theMovie timeRange:timeRange atTime:insertionTime];
}

NSDictionary * writeAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],QTMovieFlatten,nil];
// Pannello di path salvataggio

bool success = [myCombinedMovie writeToFile:savePath withAttributes:writeAttributes error:& err];




[indicatore stopAnimation:self];
NSBeep();
NSString * dove = [[NSString alloc] initWithFormat:@Video esportato in:\\\
%@,savePath];
NSRunAlertPanel(@Esportazione avvenuta con successo!,dove,@Ok,nil,nil);

if(!success)
{
NSRunAlertPanel(@Errore durante il salvataggio del video。,[err localizedDescription],nil,@Chiudi,nil,nil );
return;
return;
}
}
// Se non esiste alcun percorso
else {

NSRunAlertPanel(@Impossibile selezionare i file。,@Controlla di ,Chiudi,nil,nil);
}


解决方案

使用AVFoundation框架而不是QTKit,因为编辑/操作视频更容易(imo),虽然它似乎有点慢,代码可能不那么紧凑。



我建议您先前往阅读AVFoundation节目指南https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/AVFoundationPG.pdf



但这里有一个基本示例让你开始。在开始之前,请确保您已经链接到AVFoundation和CoreMedia框架。



除了任何其他方法或ivars,您可以添加 AVAssetExportSession * exporter NSTimer * timer ,以及一个方法 - (void)monitorProgress;



您的实现文件将包含以下方法(假设您使用称为doIt的IBAction触发方法)。不要忘记 #import< AVFoundation / AVFoundation.h> #import< CoreMedia / CoreMedia.h>

   - (IBAction)doIt:(id)sender {
//电影URL的初始数组
NSArray * myMovieURLs = [NSArray arrayWithObjects:[NSURL fileURLWithPath:@/ path / to / first.mov],[NSURL fileURLWithPath:@/ path / to / second.mov],nil];

//创建组合& A / V tracks
AVMutableComposition * comp = [AVMutableComposition composition];
AVMutableCompositionTrack * compositionVideoTrack = [comp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack * compositionAudioTrack = [comp addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

//插入开始时间的引用
CMTime startTime = kCMTimeZero;

for(int i = 0; i <[myMovieURLs count]; i ++){
//获取资源
NSURL * movieURL = [myMovieURLs objectAtIndex:i];
AVURLAsset * asset = [AVURLAsset URLAssetWithURL:movieURL options:nil];

//获取视频和音频轨道(假设视频存在 - 测试音频作为空轨道会使程序崩溃!)并插入组合轨道
AVAssetTrack * videoTrack = [[asset tracksWithMediaType :AVMediaTypeVideo] objectAtIndex:0];
bool success = [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,[asset duration])ofTrack:videoTrack atTime:startTime error:nil];

if([[asset tracksWithMediaType:AVMediaTypeAudio] count]){
AVAssetTrack * audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
success = [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,[asset duration])ofTrack:audioTrack atTime:startTime error:nil];
}

//将开始时间增加到第一个视频的结尾
startTime = CMTimeAdd(startTime,[asset duration]);
}

//设置输出URL
NSURL * outputURL = [NSURL fileURLWithPath:@/ path / to / output.mov];

/ *创建导出器。
注意预设类型由您选择。如果需要,您可以检查资产的大小(使用[asset naturalSize])或上面的其他值,并使用它来基于您的预设。
使用exportPresetsCompatibleWithAsset:获取与特定资产兼容的预设列表。
* /
NSLog(@兼容预设您可以使用:%@,[AVAssetExportSession exportPresetsCompatibleWithAsset:comp]);
exporter = [[AVAssetExportSession alloc] initWithAsset:comp presetName:AVAssetExportPreset640x480];

[exporter setOutputURL:outputURL];
[exporter setOutputFileType:AVFileTypeQuickTimeMovie];
[exporter exportAsynchronouslyWithCompletionHandler:^(void){
switch([exporter status]){
case AVAssetExportSessionStatusFailed:
NSLog(@Export failed:%@,[[exporter error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@Export canceled);
break;
默认值:
break;
}
}];

//这只是一个简单的计时器,它将调用一个方法来记录进度
timer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:@ selector(monitorProgress)
userInfo:nil
repeats:YES];
}



- (void)monitorProgress {
if([exporter progress] == 1.0){
[timer invalidate] ;
}

NSLog(@Progress:%f,[exporter progress] * 100);

}


I have just made a simple app which uses QTKit to merge two videos together

Here is the problem:

I have just discovered that if I try to merge two videos with different width & height the output is a video whose height and width is the same of the big video but contains the small one with black and wide borders.

Question:

How can i merge two videos together and get an output video with a correct format (width/height) ?

Example to understand better what i need:

I have two videos:

Video 1 = 1920 x 1280 VIdeo 2 = 1280 x 960

What i want: A video in 1920 x 1280 (Need to up-scale and crop the small one)

Code:

-(void)voidMethodToCombine {


NSError *err = nil;
QTMovie *myCombinedMovie = [[QTMovie alloc] initToWritableData:[NSMutableData data] error:&err];
if (err)
{
    NSRunAlertPanel(@"Errore nella creazione del video",[err localizedDescription], nil, @"Chiudi", nil, nil);
    return;
    return;
}


// Create the File Open Dialog class.
NSSavePanel *savePanel = [NSSavePanel savePanel]; //Dove salvo il video ?


if ([savePanel runModal])//Se premo ok
{   
    [indicatore setUsesThreadedAnimation:YES];
    [indicatore startAnimation:self];
    NSURL *saveURL = savePanel.URL;
    NSString *savePath = [saveURL path];
//Prelevo i 2 percorsi e gli inserisco negli array

NSString *video1 = [URLVideo1 stringValue];
NSString *video2 = [URLVideo2 stringValue];

NSURL *theURLvideo1 = [NSURL fileURLWithPath:video1];

NSURL *theURLvideo2 = [NSURL fileURLWithPath:video2];

if((theURLvideo1) && (theURLvideo2)) {



NSArray *myMovieURLs = [NSArray arrayWithObjects:theURLvideo1,theURLvideo2, nil];

for (NSURL *url in myMovieURLs)
{
    QTMovie *theMovie = [QTMovie movieWithURL:url error:&err];
    if (err){
        NSRunAlertPanel(@"Errore durante il caricamento di uno dei film",[err localizedDescription], nil, @"Chiudi", nil, nil);
        return;
    }
    QTTimeRange timeRange = QTMakeTimeRange(QTZeroTime, [theMovie duration]);
    QTTime insertionTime = [myCombinedMovie duration]; 
    [myCombinedMovie insertSegmentOfMovie:theMovie timeRange:timeRange atTime:insertionTime];
}

NSDictionary *writeAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], QTMovieFlatten, nil]; 
//Pannello di path salvataggio

bool success = [myCombinedMovie writeToFile:savePath withAttributes:writeAttributes error:&err];




[indicatore stopAnimation:self];
NSBeep();
NSString *dove = [[NSString alloc] initWithFormat:@"Video esportato in:\n%@",savePath];
NSRunAlertPanel(@"Esportazione avvenuta con successo!", dove, @"Ok", nil, nil);

if (!success)
{
    NSRunAlertPanel(@"Errore durante il salvataggio del video.",[err localizedDescription], nil, @"Chiudi", nil, nil);
    return;
    return;
}
}
//Se non esiste alcun percorso
else {

    NSRunAlertPanel(@"Impossibile selezionare i file.", @"Controlla di aver specificato un percorso.", @"Chiudi", nil, nil);
}

解决方案

To do this it's easiest to use AVFoundation frameworks instead of QTKit, as editing/manipulating the video is much easier (imo), though it seems to be a bit slower and the code may be less compact.

I'd suggest starting by reading the AVFoundation programming guide at https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/AVFoundationPG.pdf

But here's a basic example to get you started. Before starting, make sure you have linked against the AVFoundation and CoreMedia frameworks.

In your header besides any other methods or ivars that you may have add an AVAssetExportSession *exporter and NSTimer *timer, as well as a method - (void) monitorProgress;.

Your implementation file would then include the following methods (assuming you're triggering the method with an IBAction called doIt). And don't forget to #import <AVFoundation/ AVFoundation.h> and #import <CoreMedia/CoreMedia.h>:

- (IBAction)doIt:(id)sender {
// Initial array of movie URLs
NSArray *myMovieURLs = [NSArray arrayWithObjects:[NSURL fileURLWithPath:@"/path/to/first.mov"], [NSURL fileURLWithPath:@"/path/to/second.mov"], nil];

// Create the composition & A/V tracks
AVMutableComposition *comp = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [comp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *compositionAudioTrack = [comp addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

// A reference for insertion start time
CMTime startTime = kCMTimeZero;

for (int i=0; i< [myMovieURLs count]; i++){
    // Get asset 
    NSURL *movieURL = [myMovieURLs objectAtIndex:i];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:movieURL options:nil];

    // Get video and audio tracks (assuming video exists - test for audio as an empty track will crash the program!) and insert in composition tracks
    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    bool success = [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:videoTrack atTime:startTime error:nil];

    if ([[asset tracksWithMediaType:AVMediaTypeAudio]count]){
        AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
        success = [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:audioTrack atTime:startTime error:nil];
    }

    // increment the start time to the end of this first video
    startTime = CMTimeAdd(startTime, [asset duration]);
}

//Set the output URL
NSURL *outputURL = [NSURL fileURLWithPath:@"/path/to/output.mov"];

/* Create the exporter.  
 Note the preset type is up to you to choose.  If you wanted, you could check the asset's size (with [asset naturalSize]) or other values above and use that to base your preset on. 
 Use exportPresetsCompatibleWithAsset: to get a list of presets that are compatible with a specific asset.
 */
NSLog(@"Compat presets you could use: %@", [AVAssetExportSession exportPresetsCompatibleWithAsset:comp]);
exporter = [[AVAssetExportSession alloc] initWithAsset:comp presetName:AVAssetExportPreset640x480];

[exporter setOutputURL:outputURL];
[exporter setOutputFileType:AVFileTypeQuickTimeMovie];
[exporter exportAsynchronouslyWithCompletionHandler:^(void){
    switch ([exporter status]) {
        case AVAssetExportSessionStatusFailed:
            NSLog(@"Export failed: %@", [[exporter error] localizedDescription]);
            break;
        case AVAssetExportSessionStatusCancelled:
            NSLog(@"Export canceled");
            break;
        default:
            break;
    }
}];

// This is just a simple timer that will call a method to log the progress
timer=[NSTimer scheduledTimerWithTimeInterval:5
                                       target:self
                                     selector:@selector(monitorProgress)
                                     userInfo:nil
                                      repeats:YES];
}



-(void)monitorProgress{ 
if ([exporter progress] == 1.0){
    [timer invalidate];
}

NSLog(@"Progress: %f",[exporter progress]* 100);

}

这篇关于QTKit - 合并两个不同宽度和高度的视频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆