开发文章

FFmpeg解析直播点播m3u8

看下直播m3u8结构:

复制内容到剪贴板
  1. #EXTM3U  
  2. #EXT-X-MEDIA-SEQUENCE:3918  
  3. #EXT-X-TARGETDURATION:10  
  4. #EXTINF:10,  
  5. 2017071806/1500358480.ts?type=hls_live_slice  
  6. #EXTINF:10,  
  7. 2017071806/1500358490.ts?type=hls_live_slice  
  8. #EXTINF:10,  
  9. 2017071806/1500358500.ts?type=hls_live_slice  
  10. #EXTINF:10,  
  11. 2017071806/1500358510.ts?type=hls_live_slice  
  12. #EXTINF:10,  
  13. 2017071806/1500358520.ts?type=hls_live_slice  
  14. #EXTINF:10,  
  15. 2017071806/1500358535.ts?type=hls_live_slice  
  16. #EXTINF:10,  
  17. 2017071806/1500358545.ts?type=hls_live_slice  
  18. #EXTINF:10,  
  19. 2017071806/1500358555.ts?type=hls_live_slice  
  20. #EXTINF:10,  
  21. 2017071806/1500358565.ts?type=hls_live_slice  
  22. #EXTINF:10,  
  23. 2017071806/1500358575.ts?type=hls_live_slice  

看下点播m3u8结构:

复制内容到剪贴板
  1. #EXTM3U  
  2. #EXT-X-VERSION:3  
  3. #EXT-X-MEDIA-SEQUENCE:0  
  4. #EXT-X-TARGETDURATION:19  
  5. #EXT-X-PLAYLIST-TYPE:VOD  
  6. #EXTINF:9.800,  
  7. 00_d0024036a7j.320086.1.ts?index=0&start=0&end=9800&brs=0&bre=1509827&ver=4  
  8. #EXTINF:10.480,  
  9. 01_d0024036a7j.320086.1.ts?index=1&start=9800&end=20280&brs=1509828&bre=3828055&ver=4  
  10. #EXTINF:9.960,  
  11. 02_d0024036a7j.320086.1.ts?index=2&start=20280&end=30240&brs=3828056&bre=6248743&ver=4  
  12. #EXTINF:9.520,  
  13. 03_d0024036a7j.320086.1.ts?index=3&start=30240&end=39760&brs=6248744&bre=8234399&ver=4  
  14. #EXTINF:9.920,  
  15. 04_d0024036a7j.320086.1.ts?index=4&start=39760&end=49680&brs=8234400&bre=10619931&ver=4  
  16. #EXTINF:9.960,  
  17. 05_d0024036a7j.320086.1.ts?index=5&start=49680&end=59640&brs=10619932&bre=13400639&ver=4  
  18. #EXTINF:9.720,  
  19. 06_d0024036a7j.320086.1.ts?index=6&start=59640&end=69360&brs=13400640&bre=16777683&ver=4  
  20. #EXTINF:10.880,  
  21. 07_d0024036a7j.320086.1.ts?index=7&start=69360&end=80240&brs=16777684&bre=19713867&ver=4  
  22. ...省略  
  23. #EXTINF:9.960,  
  24. 029_d0024036a7j.320086.2.ts?index=29&start=295520&end=305480&brs=0&bre=1287611&ver=4  
  25. #EXTINF:9.040,  
  26. ...省略  
  27. #EXTINF:7.240,  
  28. 0315_d0024036a7j.320086.11.ts?index=315&start=3181360&end=3188600&brs=30080752&bre=31204615&ver=4  
  29. #EXT-X-ENDLIST  

区别:
1、 每个TS分片时间,通过标签EXTINF,后面有的是float型,有的是int型,一般为10s(也有不会10s的),最后如果没有10s,就取对应时间。
2、不是所有点播m3u8中都有EXT-X-PLAYLIST-TYPE,表明类型。最直接区分就是直播m3u8没有EXT-X-ENDLIST标签,因为是实时流,自然不会有结束,否则就是点播流了。

FFmpeg是如何解析直播,点播的HLS?在\libavformat\hlsproto.c中,就是实现步骤,先打开m3u8文件,然后parse。

复制内容到剪贴板
  1. static int hls_open(URLContext *h, const char *uri, int flags)  
  2. {  
  3.     HLSContext *s = h->priv_data;  
  4.     int ret, i;  
  5.     const char *nested_url;  
  6.   
  7.     if (flags & AVIO_FLAG_WRITE)  
  8.         return AVERROR(ENOSYS);  
  9.   
  10.     h->is_streamed = 1;  
  11.   
  12.     if (av_strstart(uri, "hls+", &nested_url)) {  
  13.         av_strlcpy(s->playlisturl, nested_url, sizeof(s->playlisturl));  
  14.     } else if (av_strstart(uri, "hls://", &nested_url)) {  
  15.         av_log(h, AV_LOG_ERROR,  
  16.                "No nested protocol specified. Specify e.g. hls+http://%s\n",  
  17.                nested_url);  
  18.         ret = AVERROR(EINVAL);  
  19.         goto fail;  
  20.     } else {  
  21.         av_log(h, AV_LOG_ERROR, "Unsupported url %s\n", uri);  
  22.         ret = AVERROR(EINVAL);  
  23.         goto fail;  
  24.     }  
  25.     av_log(h, AV_LOG_WARNING,  
  26.            "Using the hls protocol is discouraged, please try using the "  
  27.            "hls demuxer instead. The hls demuxer should be more complete "  
  28.            "and work as well as the protocol implementation. (If not, "  
  29.            "please report it.) To use the demuxer, simply use %s as url.\n",  
  30.            s->playlisturl);  
  31.   
  32.     if ((ret = parse_playlist(h, s->playlisturl)) < 0)  
  33.         goto fail;  
  34.   
  35.     if (s->n_segments == 0 && s->n_variants > 0) {  
  36.         int max_bandwidth = 0, maxvar = -1;  
  37.         for (i = 0; i < s->n_variants; i++) {  
  38.             if (s->variants[i]->bandwidth > max_bandwidth || i == 0) {  
  39.                 max_bandwidth = s->variants[i]->bandwidth;  
  40.                 maxvar = i;  
  41.             }  
  42.         }  
  43.         av_strlcpy(s->playlisturl, s->variants[maxvar]->url,  
  44.                    sizeof(s->playlisturl));  
  45.         if ((ret = parse_playlist(h, s->playlisturl)) < 0)  
  46.             goto fail;  
  47.     }  
  48.   
  49.     if (s->n_segments == 0) {  
  50.         av_log(h, AV_LOG_WARNING, "Empty playlist\n");  
  51.         ret = AVERROR(EIO);  
  52.         goto fail;  
  53.     }  
  54.     s->cur_seq_no = s->start_seq_no;  
  55.     if (!s->finished && s->n_segments >= 3)  
  56.         s->cur_seq_no = s->start_seq_no + s->n_segments - 3;  
  57.   
  58.     return 0;  
  59.   
  60. fail:  
  61.     hls_close(h);  
  62.     return ret;  
  63. }  

解析playlist中的ts流

复制内容到剪贴板
  1. static int parse_playlist(URLContext *h, const char *url)  
  2. {  
  3.     HLSContext *s = h->priv_data;  
  4.     AVIOContext *in;  
  5.     int ret = 0, is_segment = 0, is_variant = 0, bandwidth = 0;  
  6.     int64_t duration = 0;  
  7.     char line[1024];  
  8.     const char *ptr;  
  9.   
  10.     if ((ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ,  
  11.                                    &h->interrupt_callback, NULL,  
  12.                                    h->protocol_whitelist, h->protocol_blacklist)) < 0)  
  13.         return ret;  
  14.   
  15.     read_chomp_line(in, line, sizeof(line));  
  16.     if (strcmp(line, "#EXTM3U")) {  
  17.         ret = AVERROR_INVALIDDATA;  
  18.         goto fail;  
  19.     }  
  20.   
  21.     free_segment_list(s);  
  22.     s->finished = 0;  
  23.     while (!avio_feof(in)) {  
  24.         read_chomp_line(in, line, sizeof(line));  
  25.         if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {  
  26.             struct variant_info info = {{0}};  
  27.             is_variant = 1;  
  28.             ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_variant_args,  
  29.                                &info);  
  30.             bandwidth = atoi(info.bandwidth);  
  31.         } else if (av_strstart(line, "#EXT-X-TARGETDURATION:", &ptr)) {  
  32.             s->target_duration = atoi(ptr) * AV_TIME_BASE;  
  33.         } else if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {  
  34.             s->start_seq_no = atoi(ptr);  
  35.         } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) {  
  36.             s->finished = 1;  
  37.         } else if (av_strstart(line, "#EXTINF:", &ptr)) {  
  38.             is_segment = 1;  
  39.             duration = atof(ptr) * AV_TIME_BASE;  
  40.         } else if (av_strstart(line, "#", NULL)) {  
  41.             continue;  
  42.         } else if (line[0]) {  
  43.             if (is_segment) {  
  44.                 struct segment *seg = av_malloc(sizeof(struct segment));  
  45.                 if (!seg) {  
  46.                     ret = AVERROR(ENOMEM);  
  47.                     goto fail;  
  48.                 }  
  49.                 seg->duration = duration;  
  50.                 ff_make_absolute_url(seg->url, sizeof(seg->url), url, line);  
  51.                 dynarray_add(&s->segments, &s->n_segments, seg);  
  52.                 is_segment = 0;  
  53.             } else if (is_variant) {  
  54.                 struct variant *var = av_malloc(sizeof(struct variant));  
  55.                 if (!var) {  
  56.                     ret = AVERROR(ENOMEM);  
  57.                     goto fail;  
  58.                 }  
  59.                 var->bandwidth = bandwidth;  
  60.                 ff_make_absolute_url(var->url, sizeof(var->url), url, line);  
  61.                 dynarray_add(&s->variants, &s->n_variants, var);  
  62.                 is_variant = 0;  
  63.             }  
  64.         }  
  65.     }  
  66.     s->last_load_time = av_gettime_relative();  
  67.   
  68. fail:  
  69.     avio_close(in);  
  70.     return ret;  
  71. }  

 

感谢 逆流的鱼yuiop 支持 磐实编程网 原文地址:
blog.csdn.net/hejjunlin/article/details/75305299

文章信息

发布时间:2017-07-27

作者:逆流的鱼yuiop

发布者:aquwcw

浏览次数: