Как заставить QTMovie воспроизводить файл с URL с принудительным (MP3) типом? - PullRequest
5 голосов
/ 09 декабря 2010

Я использую QTKit для постепенной загрузки и воспроизведения MP3 с URL.Согласно этой документации , это код, который я должен использовать для достижения этой цели:

NSURL *mp3URL = [NSURL URLWithString:@"http://foo.com/bar.mp3"];

NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];

Это работает и выполняет именно то, что я хочу - URL-адрес MP3 загружается и начинает воспроизводитьсянемедленно.Однако, если URL не имеет расширения пути «.mp3», происходит сбой:

NSURL *mp3URL = [NSURL URLWithString:@"http://foo.com/bar"];

NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];

Не выдается ошибка, исключение не возникает;длительность звука просто установлена ​​на ноль, и ничего не воспроизводится.

Единственный способ, который я нашел, чтобы обойти это, - принудительно вызвать тип, загрузив данные вручную и используя QTDataReference:

NSURL *mp3URL = [NSURL URLWithString:@"http://foo.com/bar"];
NSData *mp3Data = [NSData dataWithContentsOfURL:mp3URL];

QTDataReference *dataReference = 
    [QTDataReference dataReferenceWithReferenceToData:mp3Data
                                                 name:@"bar.mp3"
                                             MIMEType:nil];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithDataReference:dataReference error:&error];
[sound play];

Однако это вынуждает меня полностью загрузить ВСЕ файлы MP3 синхронно, прежде чем я смогу начать их воспроизведение, что, очевидно, нежелательно.Есть ли способ обойти это?

Спасибо.

Редактировать

На самом деле, кажется, что расширение пути не имеет к этому никакого отношения;Content-Type просто не устанавливается в заголовке HTTP.Несмотря на это, последний код работает, а первый - нет.Кто-нибудь знает способ исправить это, не имея доступа к серверу?

Редактировать 2

Кто-нибудь?Я нигде не могу найти информацию об этом , и Google разочарованно теперь показывает эту страницу как лучший результат для большинства моих запросов ...

Ответы [ 4 ]

0 голосов
/ 25 мая 2012

Просто создайте экземпляр, подобный этому ...

QTMovie *aPlayer  = [QTMovie movieWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                                 fileUrl, QTMovieURLAttribute,
                                                 [NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute,
                                                 /*[NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute,*/
                                                 nil] error:error];
0 голосов
/ 14 декабря 2010

Если вы подумали, что первое решение *1001* Вейкселя было хакерским, вы собираетесь love вот это:

Виновником является заголовок Content-Type, так как выопределили.Если бы QTKit.framework использовал Objective-C внутри, это было бы тривиальным вопросом переопределения -[NSHTTPURLResponse allHeaderFields] с категорией по вашему выбору.Однако QTKit.framework (в лучшую или в худшую сторону) использует Core Foundation (и Core Services) для внутреннего использования.Обе эти платформы основаны на C, и в C. не существует элегантного способа переопределения функций.

Тем не менее, - это метод, но не симпатичный.Взаимодействие функций даже задокументировано Apple, но, похоже, немного отстает от времени, по сравнению с остальной частью их документации.

По сути, вы хотите что-то вроде следующего:

typedef struct interpose_s {
    void *new_func;
    void *orig_func;
} interpose_t;

CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
                                                 CFHTTPMessageRef message,
                                                 CFStringRef headerField
                                                 );

static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) = {
    { (void *)myCFHTTPMessageCopyHeaderFieldValue, (void *)CFHTTPMessageCopyHeaderFieldValue }
};

CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
                                                 CFHTTPMessageRef message,
                                                 CFStringRef headerField
                                                 ) {
    if (CFStringCompare(headerField, CFSTR("Content-Type"), 0) == kCFCompareEqualTo) {
        return CFSTR("audio/x-mpeg");
    } else {
        return CFHTTPMessageCopyHeaderFieldValue(message, headerField);
    }
}

Возможно, вы захотите добавить логику, специфичную для вашего приложения, с точки зрения обработки поля Content-Type, чтобы ваше приложение не ломалось странными и чудесными способами, когда каждый HTTP-запрос определен как аудиофайл.

0 голосов
/ 27 декабря 2010

Попробуйте заменить http:// на icy://.

0 голосов
/ 12 декабря 2010

Две идеи. (Первый немного хакерский):
Чтобы обойти отсутствующий тип контента, вы можете встроить небольшой веб-сервер Cocoa, который дополняет поле отсутствующего заголовка, и направить NSURL через этот «прокси».

Некоторые реализации HTTP-сервера Cocoa:

Вторым будет переключение на каркас более низкого уровня (с QTKit на AudioToolbox).
Вам понадобится больше кода, но есть несколько очень хороших ресурсов о том, как транслировать mp3 с помощью AudioToolbox.
например.: http://cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html

Лично я бы пошел со вторым вариантом. AudioToolbox не так прост, как QTKit, но предлагает чистое решение вашей проблемы. Он также доступен как для iOS, так и для Mac OS, поэтому вы найдете много информации.

Обновление:
Вы пытались использовать другой инициализатор? например

+ (id)movieWithAttributes:(NSDictionary *)attributes error:(NSError **)errorPtr

Вы можете вставить свой URL для ключа QTMovieURLAttribute и, возможно, вы можете компенсировать отсутствующий тип контента, предоставив другие атрибуты в этом словаре. Этот проект с открытым исходным кодом имеет категорию QTMovie, которая содержит методы для выполнения похожих задач: http://vidnik.googlecode.com/svn-history/r63/trunk/Source/Categories/QTMovie+Async.m

...