Обнаружение mime-типа в памяти с помощью Cocoa (OS X)?
-
08-07-2019 - |
Вопрос
Мое приложение представляет собой программу просмотра пользовательского формата, zip-файл с четко определенным XML-манифестом и ресурсами, такими как изображения и фильмы.Я использую zlib, чтобы открыть zip-файл в памяти, а затем приступить к отображению указанных ресурсов.
Одна из проблем, с которой я столкнулся, заключается в том, что я не могу правильно отображать видео, по-видимому, потому, что QTMovie не может определить тип mime.Фильм, загруженный из файла ([QTMovie MovieWithFile]), работает отлично.Загружаемый из памяти ([QTMovie MovieWithData]) работать отказывается.
Это имеет смысл, поскольку из-за отсутствия расширения файла QTMovie не может определить информацию о MIME-типе.После небольшого поиска я прибег к использованию QTDataReference следующим образом:
NSData *movieData = ...read from memory...;
QTDataReference *movieDataReference = [[QTDataReference alloc] initWithReferenceToData:movieData name:fileName MIMEType:@"video/x-m4v"];
QTMovie *mov = [QTMovie movieWithDataReference:movieDataReference error:&err];
Это работает хорошо, однако жесткое кодирование MIMEType далеко от идеала.У меня есть доступ к имени файла и расширению, поэтому я попытался найти mime-тип с помощью UTI (спасибо ребятам из #macdev):
- (NSString*)mimeTypeForExtension:(NSString*)ext {
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,(CFStringRef)ext,NULL);
return NSMakeCollectable(UTTypeCopyPreferredTagWithClass((CFStringRef)UTI,kUTTagClassMIMEType));
}
Однако это не работает.Очевидно, что где-то существует внутренняя база данных расширений и соответствующих mime-типов OS X.В противном случае фильмы с диска не будут работать.Как мне получить к нему доступ?
Спасибо!
Решение
Проблема, с которой вы столкнулись, заключается в том, что m4v и m4p не имеют типов mime, зарегистрированных в службах запуска (вероятно, потому, что тип mime для m4v и m4p не является стандартным).В любом случае вам, вероятно, следует обрабатывать такие крайние случаи, а затем проверять ноль, когда функция возвращает значение (в случае, если расширение не зарегистрировано и не обрабатывается вами).
Другое дело, что при текущем использовании у вас происходит утечка памяти.Я предполагаю, что вы используете сборку мусора, но первый вызов создает CFString, которая никогда не высвобождается.Вот предлагаемая реализация вашего метода:
-(NSString*)mimeTypeForExtension:(NSString*)ext
{
NSAssert( ext, @"Extension cannot be nil" );
NSString* mimeType = nil;
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
(CFStringRef)ext, NULL);
if( !UTI ) return nil;
CFStringRef registeredType = UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType);
if( !registeredType ) // check for edge case
{
if( [ext isEqualToString:@"m4v"] )
mimeType = @"video/x-m4v";
else if( [ext isEqualToString:@"m4p"] )
mimeType = @"audio/x-m4p";
// handle anything else here that you know is not registered
} else {
mimeType = NSMakeCollectable(registeredType);
}
CFRelease(UTI);
return mimeType;
}
Другие советы
Вы можете использовать NSWorkspace, чтобы система угадывала UTI файла.
-(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err {
NSString *uti, *mimeType = nil;
if (!(uti = [[NSWorkspace sharedWorkspace] typeOfFile:path error:err]))
return nil;
if (err)
*err = nil;
if ((mimeType = (NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)uti, kUTTagClassMIMEType)))
mimeType = NSMakeCollectable(mimeType);
return mimeType;
}
Предложите людям изменить возврат на [mimeType autorelease];- некоторые из нас до сих пор используют древние способы!
И спасибо!Это была большая помощь.