NTP时间戳转换

2019-06-15  本文已影响0人  RoaringMe

场景

腾讯视频云直播答题NTP时间同步方案是在推流 URL 之后添加 &txAddTimestamp=2 参数(之前的txAddTimestamp=1会在小程序上遭遇播放黑屏问题),由服务器在视频流每一帧打入一个带有国际标准时间(误差在 100ms 以内)的 SEI 时间戳。通过TXLiteAVSDK的 PLAY_EVT_GET_MESSAGE 消息事件获取的是一个8字节的64位时间戳。以下介绍了如何把这个8字节的64位时间戳转换成Unix时间戳。

原理图

iOS转换Unix时间戳

-(void) onPlayEvent:(int)EvtID withParam:(NSDictionary*)param
{
    NSDictionary* dict = param;
    
    dispatch_async(dispatch_get_main_queue(), ^{
        //消息事件
        if (EvtID == PLAY_EVT_GET_MESSAGE) {
            //事件戳转换
            long tv = [self byteArrayToInt:param[@"EVT_GET_MSG"]];;
            long sv = tv / 1000;    // 服务器返回的是毫秒Unix timestamp,这里转换成秒
            NSLog(@"time %ld", sv);
        } 
    });
}

-(long)byteArrayToInt:(NSData *)data {
    Byte *byteArray = (Byte *)data.bytes;
    int a_len = 8;
    Byte *a = (Byte *)malloc(a_len);
    int i = a_len - 1;
    int j = (int)data.length - 1;
    for (; i >= 0; i--, j--) {// 从b的尾部(即int值的低位)开始copy数据
        if (j >= 0)
            a[i] = byteArray[j];
        else
            a[i] = 0;// 如果b.length不足4,则将高位补0
    }
    // 注意此处和byte数组转换成int的区别在于,下面的转换中要将先将数组中的元素转换成long型再做移位操作,
    // 若直接做位移操作将得不到正确结果,因为Java默认操作数字时,若不加声明会将数字作为int型来对待,此处必须注意。
    long v0 = (long) (a[0] & 0xff) << 56;// &0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位
    long v1 = (long) (a[1] & 0xff) << 48;
    long v2 = (long) (a[2] & 0xff) << 40;
    long v3 = (long) (a[3] & 0xff) << 32;
    long v4 = (long) (a[4] & 0xff) << 24;
    long v5 = (long) (a[5] & 0xff) << 16;
    long v6 = (long) (a[6] & 0xff) << 8;
    long v7 = (long) (a[7] & 0xff);
    free(a);
    return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7;
}

Android转换Unix时间戳

long timeStamp = byteArrayToInt(param.getByteArray(TXLiveConstants.EVT_GET_MSG));
/**
* 将8字节的byte数组转成一个long值
*/
public static long byteArrayToInt(byte[] byteArray) {
        byte[] a = new byte[8];
        int i = a.length - 1, j = byteArray.length - 1;
        for (; i >= 0; i--, j--) {// 从b的尾部(即int值的低位)开始copy数据
            if (j >= 0)
                a[i] = byteArray[j];
            else
                a[i] = 0;// 如果b.length不足4,则将高位补0
        }
        // 注意此处和byte数组转换成int的区别在于,下面的转换中要将先将数组中的元素转换成long型再做移位操作,
        // 若直接做位移操作将得不到正确结果,因为Java默认操作数字时,若不加声明会将数字作为int型来对待,此处必须注意。
        long v0 = (long) (a[0] & 0xff) << 56;// &0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位
        long v1 = (long) (a[1] & 0xff) << 48;
        long v2 = (long) (a[2] & 0xff) << 40;
        long v3 = (long) (a[3] & 0xff) << 32;
        long v4 = (long) (a[4] & 0xff) << 24;
        long v5 = (long) (a[5] & 0xff) << 16;
        long v6 = (long) (a[6] & 0xff) << 8;
        long v7 = (long) (a[7] & 0xff);
        return v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7;
}

示例

运行示例图 转换示例图
上一篇下一篇

猜你喜欢

热点阅读