M3U8格式视频下载

转载自:  http://blog.youkuaiyun.com/YQXH_Wang/article/details/49477131

M3U8是一种流媒体,现多用于视频播放。当把m3u8格式视频的url下载下来用文本打开会发现其实只是一段字符串,包含了很多视频小片段的地址,那么怎么样把整个视频下载下来用于本地播放呢?

首先,m3u8展开后的字符串类似这样:

<code class="hljs ruby has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXTM3U</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXT-X-TARGETDURATION:30</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXT-X-VERSION:2</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXT-X-DISCONTINUITY</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXTINF:10,</span>
 <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">http:</span>/<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/f.youku.com/player</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/getMpegtsPath/st</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/flv/fileid</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/03000201004F4BC6AFD0C202E26EEEB41666A0-C93C-D6C9-9FFA-33424A776707/ipad</span>0_<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>.ts?<span class="hljs-constant" style="box-sizing: border-box;">KM</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>eb49fe4969126c6&start=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>&<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">end</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>&ts=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>&html5=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>&seg_no=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>&seg_time=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXTINF:20,</span>
 <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">http:</span>/<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/f.youku.com/player</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/getMpegtsPath/st</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/flv/fileid</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/03000201004F4BC6AFD0C202E26EEEB41666A0-C93C-D6C9-9FFA-33424A776707/ipad</span>0_1.ts?<span class="hljs-constant" style="box-sizing: border-box;">KM</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>eb49fe4969126c6&start=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>&<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">end</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>&ts=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>&html5=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>&seg_no=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>&seg_time=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXTINF:20,</span>
 <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">http:</span>/<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/f.youku.com/player</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/getMpegtsPath/st</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/flv/fileid</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/03000201004F4BC6AFD0C202E26EEEB41666A0-C93C-D6C9-9FFA-33424A776707/ipad</span>0_2.ts?<span class="hljs-constant" style="box-sizing: border-box;">KM</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>eb49fe4969126c6&start=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>&<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">end</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">50</span>&ts=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>&html5=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>&seg_no=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>&seg_time=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXTINF:20,</span>
 <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">http:</span>/<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/f.youku.com/player</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/getMpegtsPath/st</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/flv/fileid</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/03000201004F4BC6AFD0C202E26EEEB41666A0-C93C-D6C9-9FFA-33424A776707/ipad</span>0_3.ts?<span class="hljs-constant" style="box-sizing: border-box;">KM</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>eb49fe4969126c6&start=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">50</span>&<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">end</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">70</span>&ts=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>&html5=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>&seg_no=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>&seg_time=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXTINF:24,</span>
 <span class="hljs-symbol" style="color: rgb(0, 102, 102); box-sizing: border-box;">http:</span>/<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/f.youku.com/player</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/getMpegtsPath/st</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/flv/fileid</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/03000201004F4BC6AFD0C202E26EEEB41666A0-C93C-D6C9-9FFA-33424A776707/ipad</span>0_4.ts?<span class="hljs-constant" style="box-sizing: border-box;">KM</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>eb49fe4969126c6&start=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">70</span>&<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">end</span>=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">98</span>&ts=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>&html5=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>&seg_no=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>&seg_time=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>
 <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#EXT-X-ENDLIST</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

在每一行#EXTINF:下面的网址就是一个个ts文件的地址,实际去下载的是这些小片段。而在#EXTINF:后面的数字代表的是这个ts文件所包含视频的时长。

所以第一步要解析这个m3u8的url,将其中所有ts文件的下载地址记录下来:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *data = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> stringWithContentsOfURL:url usedEncoding:&encoding error:&error];
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSMutableArray</span> *segments = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSMutableArray</span> array];
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSRange</span> segmentRange = [remainData rangeOfString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#EXTINF:"</span>];
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSInteger</span> segmentIndex = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSInteger</span> totalSeconds = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (segmentRange<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span> != <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSNotFound</span>) {
    SCM3U8SegmentInfo *segment = [[SCM3U8SegmentInfo alloc] init];
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//读取片段时长</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSRange</span> commaRange = [remainData rangeOfString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">","</span>];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *value = [remainData substringWithRange:NSMakeRange(segmentRange<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span> + [@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#EXTINF:"</span> length], commaRange<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span> -(segmentRange<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span> + [@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#EXTINF:"</span> length]))];
    segment<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.duration</span> = [value intValue];
    totalSeconds+=segment<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.duration</span>;
    remainData = [remainData substringFromIndex:commaRange<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span>];
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//读取片段url</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSRange</span> linkRangeBegin = [remainData rangeOfString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http"</span>];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSRange</span> linkRangeEnd = [remainData rangeOfString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#"</span>];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *linkurl = [remainData substringWithRange:NSMakeRange(linkRangeBegin<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span>, linkRangeEnd<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span> - linkRangeBegin<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span>)];
    segment<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.url</span> = linkurl;
    segment<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.index</span> = segmentIndex;
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//</span>
    segmentIndex++;
    [segments addObject:segment];
    remainData = [remainData substringFromIndex:linkRangeEnd<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.location</span>];
    segmentRange = [remainData rangeOfString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#EXTINF:"</span>];
}
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>

然后得到了这些文件的地址后,就可以去下载了。下载方法有很多,可以用NSURLConnection,NSURLSession,ASIHTTPRequest,AFNetworking等。注意因为一个视频包含很多个小的ts文件,所以为了便于管理,建议1 是将这些文件按索引号分别命名为id0.ts,id1.ts,id2.ts等,2 是按顺序去下载这些小片段,且同一时间只下载一个,当一个下载完成后,再去下载下一个。

接着当所有这些ts文件下载完成后,需要将它们在本地拼接成一个新的m3u8文件:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *pathPrefix = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">YES</span>) objectAtIndex:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *saveTo = [[pathPrefix stringByAppendingPathComponent:kPathDownload] stringByAppendingPathComponent:<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.vid</span>];
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *fullPath = [saveTo stringByAppendingPathComponent:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"movie.m3u8"</span>];
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//创建文件头部</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span>* head = @<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#EXTM3U\n#EXT-X-TARGETDURATION:30\n#EXT-X-VERSION:2\n#EXT-X-DISCONTINUITY\n"</span>;
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span>* segmentPrefix = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> stringWithFormat:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://127.0.0.1:54321/%@/"</span>,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.vid</span>];
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSInteger</span> count = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.segmentList</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.segments</span> count];
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//填充片段数据</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;i<count;i++)
{
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *filename = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> stringWithFormat:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"id%d.ts"</span>,i];
    SCM3U8SegmentInfo *segInfo = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.segmentList</span> getSegmentWithIndex:i];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *length = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> stringWithFormat:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#EXTINF:%ld,\n"</span>,(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span>)segInfo<span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.duration</span>];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *url = [segmentPrefix stringByAppendingString:filename];
    head = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> stringWithFormat:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@%@%@\n"</span>,head,length,url];
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//创建尾部</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span>* end = @<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"#EXT-X-ENDLIST"</span>;
head = [head stringByAppendingString:end];
NSMutableData *writer = [[NSMutableData alloc] init];
[writer appendData:[head dataUsingEncoding:NSUTF8StringEncoding]];
[writer writeToFile:fullPath atomically:<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">YES</span>];
</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

其中http://127.0.0.1是随便写的,只要和播放时调用的一致即可。拼成后本地的m3u8文件用文本打开类似如下

<code class="hljs vala has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTM3U</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXT-X-TARGETDURATION:30</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXT-X-VERSION:2</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXT-X-DISCONTINUITY</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id0.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id1.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id2.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id3.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id4.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id5.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id6.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id7.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXTINF:6,</span>
http:<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//127.0.0.1:54321/TTT/id8.ts</span>
<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#EXT-X-ENDLIST</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

最后由于m3u8只支持http协议的远程播放,所以必须在应用程序里搭建一个服务器。好消息是早就有开源库CocoaHTTPServer做到了这一点

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)setHttpServer
{
    _httpServer = [[HTTPServer alloc] init];
    [_httpServer setType:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"_http._tcp."</span>];
    [_httpServer setPort:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">54321</span>];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *pathPrefix = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">YES</span>) objectAtIndex:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *webPath = [pathPrefix stringByAppendingPathComponent:kPathDownload];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Setting document root: %@"</span>, webPath);
    [_httpServer setDocumentRoot:webPath];
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSError</span> *error;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(![_httpServer start:&error])
    {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Error starting HTTP Server: %@"</span>, error);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

综上,将类似@”http://127.0.0.1:54321/%@/movie.m3u8“这样的地址传给你的播放器就可以实现本地播放了。

完整项目地址为 https://github.com/wangqi211/M3U8VideoDownloadDemo


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值