5

我正在使用 QTKit 从 URL 逐步下载和播放 MP3。根据此文档,这是我应该用来完成此操作的代码:

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

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

这行得通,并且完全符合我的要求 - MP3 URL 被延迟下载并立即开始播放。但是,如果 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

任何人?我在任何地方都找不到这方面的信息,而且谷歌现在令人沮丧地将此页面显示为我大多数查询的顶部结果......

4

4 回答 4

0

两个想法。(第一个有点笨拙):
要解决缺少的内容类型,您可以嵌入一个小型 Cocoa 网络服务器来补充缺少的标头字段并通过该“代理”路由您的 NSURL。

一些 Cocoa http 服务器实现:

第二个是切换到较低级别的框架(从 QTKit 到 AudioToolbox)。
您需要更多代码,但有一些非常好的资源可以帮助您了解如何使用 AudioToolbox 流式传输 mp3。
例如: 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

于 2010-12-12T12:40:25.367 回答
0

如果您认为weichsel 的第一个解决方案是 hacky,那么您会喜欢这个:

正如您所确定的,罪魁祸首是Content-Type标题。如果在内部使用了 Objective-C,那么用您选择的类别QTKit.framework覆盖这将是一件微不足道的事情。-[NSHTTPURLResponse allHeaderFields]但是,QTKit.framework(无论好坏)在内部使用核心基础(和核心服务)。这些都是基于 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 请求都被确定为音频文件时以奇怪而奇妙的方式中断。

于 2010-12-14T07:25:46.137 回答
0

只需创建一个这样的实例...

QTMovie *aPlayer  = [QTMovie movieWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
                                                 fileUrl, QTMovieURLAttribute,
                                                 [NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute,
                                                 /*[NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute,*/
                                                 nil] error:error];
于 2012-05-25T13:08:18.943 回答
0

尝试替换http://icy://.

于 2010-12-27T20:05:50.443 回答