HLS学习(六)HLSDownloader源码分析(5)解析Media PlayList

解析Media PlayList




    PlayList就是m3u8文件或者索引文件,Media PlayList也叫媒体播放列表或者媒体索引文件


    解析Media PlayList的流程如下:
    1、如果hls_media_playlist结构体中媒体信息存在,那么先删除
    2、如果Media PlayList文件已经存在,那么先删除。没有Master PlayList的时候,这种情况就会存在,因为前面已经下载了PlayList,这个PlayList有可能是Media PlayList,也有可能是Master PlayList
    3、根据URL下载Media PlayList文件
    4、计算Media PlayList中URL的数量,每一个URL表示了一个TS视频片段
    5、分配hls_media_playlist结构体中的媒体信息数组的内存

    6、解析并格式化Media PlayList中的URL

// 处理Media PlayList
int handle_hls_media_playlist(struct hls_media_playlist *me,std::string user_agent)
{
	// 加密类型
    me->encryption = false;
    me->encryptiontype = ENC_NONE;

	// 先删除媒体信息
    if(me->media_segment !=NULL){
        delete [] me->media_segment;
    }

	// 如果Media PlayList已经存在(没有Master PlayList的时候就是这种情况),那么先释放掉
    if(me->source != NULL){
        free(me->source) ;
    }

	// 根据URL获取数据
    get_data_from_url(me->url, &me->source, NULL, STRING,user_agent);

	// 获取PlayList的类型
    if (get_playlist_type(me->source) != MEDIA_PLAYLIST) {
        return 1;
    }

	// 得到Media PlayList中URL的数量,一个URL表示了一个TS视频片段
    me->count = get_link_count(me->source);

    me->media_segment = new hls_media_segment[me->count];//(hls_media_segment *)malloc(sizeof(struct hls_media_segment) * me->count);

	// 获取Media PlayList中的URL
    if (media_playlist_get_links(me,user_agent)) {
        MSG_ERROR("Could not parse links. Exiting.\n");
        return 1;
    }
    return 0;
}


解析Media PlayList中的URL

// 解析Media PlayList中的URL
static int media_playlist_get_links(struct hls_media_playlist *me,std::string user_agent)
{
    int ms_init = media_playlist_get_media_sequence(me->source);
    int target_duration=media_playlist_get_media_target_duration(me->source);
    if(target_duration!=0){
        me->target_duration=target_duration;
    }
    struct hls_media_segment *ms = me->media_segment;
    char *src = me->source;
    char * tmp_url = (char *)malloc(strlen(src));
    
    for (int i = 0; i < me->count && src!=NULL; i++) {
        while (src != NULL) {
            if (*src == '\n') {
                src = next_line(src);
                continue;
            }
            if (*src == '#') {
                parse_playlist_tag(me, src,user_agent); // 下载密钥
                src = next_line(src);
                continue;
            }
            if (*src == '\0') {
                goto finish;
            }
            if (sscanf(src, "%[^\n]", tmp_url) == 1) {
                ms[i].sequence_number = i + ms_init;
                extend_url(&tmp_url, me->url); // 格式化URL
                ms[i].url=std::string(tmp_url);

				// 如果需要解密
                if (me->encryptiontype == ENC_AES128 || me->encryptiontype == ENC_AES_SAMPLE) {
                    memcpy(ms[i].enc_aes.key_value, me->enc_aes.key_value, KEYLEN);
                    if (me->enc_aes.iv_is_static == false) {
                        char iv_str[STRLEN_BTS(KEYLEN)];
                        snprintf(iv_str, STRLEN_BTS(KEYLEN), "%032x\n", ms[i].sequence_number);
                        uint8_t *iv_bin = (uint8_t *)malloc(KEYLEN);
                        str_to_bin(iv_bin, iv_str, KEYLEN);
                        memcpy(ms[i].enc_aes.iv_value, iv_bin, KEYLEN);
                        free(iv_bin);
                    }
                }
                src = next_line(src);
                break;
            }
        }
    }

finish:
    // Extend the individual urls.
    // for (int i = 0; i < me->count; i++) {
    //     extend_url(&ms[i].url, me->url);
    // }
    free(tmp_url);
    return 0;
}



计算TS视频片段的序号

// 计算TS视频片段的序号
static int media_playlist_get_media_sequence(char *source)
{
    int j = 0;
	
	// 序号字段用#EXT-X-MEDIA-SEQUENCE来标识
    char *p_media_sequence = strstr(source, "#EXT-X-MEDIA-SEQUENCE:");

    if (p_media_sequence) {
        if (sscanf(p_media_sequence, "#EXT-X-MEDIA-SEQUENCE:%d", &j) != 1) {
            MSG_ERROR("Could not read EXT-X-MEDIA-SEQUENCE\n");
            return 0;
        }
    }
    return j;
}



计算TS视频片段的最大时长


    所有的视频片段的时长都不能超过它

// 计算TS视频片段的最大时长,这些视频片段的时长都不能超过它
static int media_playlist_get_media_target_duration(char *source)
{
    int j = 1;
	
	// 最大时长字段使用#EXT-X-TARGETDURATION来标识
    char *p_media_sequence = strstr(source, "#EXT-X-TARGETDURATION:");

    if (p_media_sequence) {
        if (sscanf(p_media_sequence, "#EXT-X-TARGETDURATION:%d", &j) != 1) {
            MSG_ERROR("Could not read EXT-X-MEDIA-TARGETDURATION\n");
            return 0;
        }
    }
    return j;
}


下载密钥

    判断是否需要解密处理,如果需要,那么进行解密,然后根据解析出来的uri,下载key-file(即密钥)

// 判断是否需要解密处理,如果需要,那么进行解密,然后根据解析出来的uri,下载key-file(即密钥)
static int parse_playlist_tag(struct hls_media_playlist *me, char *tag,std::string user_agent)
{
    int enc_type;

	// 加密解密处理
    if (!strncmp(tag, "#EXT-X-KEY:METHOD=AES-128", 25)) {
        enc_type = ENC_AES128;
    } else if (!strncmp(tag, "#EXT-X-KEY:METHOD=SAMPLE-AES", 28)) {
        enc_type = ENC_AES_SAMPLE;
    } else  {
        return 1; // 不需要解密
    }

    me->encryption = true;
    me->encryptiontype = enc_type;
    me->enc_aes.iv_is_static = false;
        
    char *link_to_key = (char *)malloc(strlen(tag) + strlen(me->url) + 10);
    char iv_str[STRLEN_BTS(KEYLEN)];
        
    if (sscanf(tag, "#EXT-X-KEY:METHOD=AES-128,URI=\"%[^\"]\",IV=0x%s", link_to_key, iv_str) == 2 ||
        sscanf(tag, "#EXT-X-KEY:METHOD=SAMPLE-AES,URI=\"%[^\"]\",IV=0x%s", link_to_key, iv_str) == 2)
    {
        uint8_t *iv_bin = (uint8_t *)malloc(KEYLEN);
        str_to_bin(iv_bin, iv_str, KEYLEN);
        memcpy(me->enc_aes.iv_value, iv_bin, KEYLEN);
        me->enc_aes.iv_is_static = true;
        free(iv_bin);
    }
        
    extend_url(&link_to_key, me->url);

    uint8_t *decrypt;
	// 下载密钥
    if (get_data_from_url(link_to_key, NULL, &decrypt, BINKEY,user_agent) == 0) {
        MSG_ERROR("Getting key-file failed.\n");
        free(link_to_key);
        return 1;
    }

    memcpy(me->enc_aes.key_value, decrypt, KEYLEN);
    free(link_to_key);
    free(decrypt);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值