Объединяйте и конвертируйте MP3 файлы, используя QTKit - PullRequest
0 голосов
/ 13 августа 2010

Я пытаюсь объединить два .mp3 в один файл .wav, используя QTKit. Вроде бы работает, но последние несколько секунд второго файла обрезаются. Есть идеи?

- (IBAction)combineSelectedFilesAndOutputAsWAV {
    QTMovie *movie = [QTMovie movieWithFile:fileOne error:NULL];
    [movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];  
    QTMovie *segmentTwo = [QTMovie movieWithFile:fileTwo error:NULL];
    QTTimeRange range = { .time = QTZeroTime, .duration = [segmentTwo duration] };
    [segmentTwo setSelection:range];
    [movie appendSelectionFromMovie:segmentTwo];
    while([[movie attributeForKey:QTMovieLoadStateAttribute] longValue] != 100000L) {
        //wait until QTMovieLoadStateComplete
    }
    NSDictionary *exportAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                     [NSNumber numberWithBool:YES], QTMovieExport,
                                     [NSNumber numberWithLong:kQTFileTypeWave], QTMovieExportType, nil];
    NSString *outputFile = [NSString stringWithFormat:@"%@.wav", outputFilename];
    NSString *filepath = [destinationDirectory stringByAppendingPathComponent:outputFile];
    if (![movie writeToFile:filepath withAttributes:exportAttributes]) {
       //ERROR
    } 
}

(игнорировать цикл while, ожидающий QTMovieLoadStateComplete. Я переключусь на использование уведомлений в будущем. Но сейчас это не должно иметь значения ...)

Ответы [ 3 ]

2 голосов
/ 15 сентября 2010

1) Как правило, нет возможности быстро получить точную длительность произвольного файла MP3.Единственный надежный способ - расшифровать весь файл.Это верно даже для файлов CBR (некоторые кодировщики MP3 не обеспечивают точный битрейт).Поэтому [длительность сегмента] может не подходить для случаев, когда требуется точная продолжительность.Для ваших кукол вы можете попытаться использовать что-то вроде [длительность сегмента] + дельта или даже MaxDuration вместо [длительность сегмента].

2) В некоторых случаях (по крайней мере, если форматы объединенных файлов одинаковы) вы можете просто объединить файлы как двоичные данные (без использования QTKit).Более дорого: напишите заголовок RIFF-WAV для целевого файла;добавление звукового потока из первого файла (то есть исходного файла, исключая заголовки и хвостовые теги, если они есть);добавить звуковой поток из второго файла;обновить заголовок RIFF-WAV.

0 голосов
/ 04 ноября 2010

Вы также можете просто установить загрузчик фильма / mp3 как синхронный, а не асинхронный, используя атрибут QTMovieOpenAsyncOKAttribute, например:

NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:NO] , QTMovieOpenAsyncOKAttribute,
    @"path to file", QTMovieFileNameAttribute,
    [NSNumber numberWithBool:YES], QTMovieEditableAttribute,
     nil];
QTMovie *myMovie = [QTMovie movieWithAttributes:movieAttributes error:nil];

, поэтому длительность должна быть правильной, когда вы проверяете ее следующим образом:

[[myMovie attributeForKey:QTMovieDurationAttribute] QTTimeValue].timeValue;
0 голосов
/ 21 сентября 2010

Похоже, что реальная проблема заключалась в том, что я делал запросы к объекту QTMovie сразу после его создания. Прежде чем запрашивать продолжительность объекта QTMovie, вы должны убедиться, что он полностью загружен. Я добавил следующее:

- (void)pasteSegmentToConcatenatedFile:(QTMovie *)segment {
    NSLog(@"LoadStateChanged for movie : %@", segment);
    if ([[segment attributeForKey:QTMovieLoadStateAttribute] longValue] >= kMovieLoadStateComplete) {
        NSLog(@"The movie is fully loaded.");
        QTTimeRange range = { .time = QTZeroTime, .duration = [segment duration] };
        [segment setSelection:range];
        [concatenatedFile appendSelectionFromMovie:segment];
        [self convertAndOutputConcatenatedMovie];
    }
}

Этот метод будет вызываться всякий раз, когда изменяется LoadState объекта QTMovie:

QTMovie *segmentTwo = [QTMovie movieWithFile:fileTwo error:NULL];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pasteSegmentToConcatenatedFile:) name:QTMovieLoadStateDidChangeNotification object:segmentTwo];
...