SOP TRTC SDK 仪表盘 Android TRTC 发送自定义采集的视频数据 Android TRTC 发送自定义采集音频解决方案 Android TRTC 实现横屏视频通话 iOS端 TRTC 发送自定义采集视频解决方案 iOS端 TRTC 发送自定义采集音频解决方案 APNS推送 脏字过滤 TXLiteAVSDK中使用 AVAudioSession 问题总结 AndroidStudio编译SDK报错 RoomService部署验证 Xcode编译SDK报错 iOS编译库冲突问题 iOS端移动直播自定义采集实现 iOS端TXLiteAVSDK与IMSDK 3.x集成冲突报错问题 Android端TXLiteAVSDK与IMSDK 3.x集成冲突报错问题 Android端LiteIM sdk升级IM4.x版本报错问题 移动直播iOS 12兼容问题 如何实现好的画质 如何计算PCM音量大小 使用播放器播放视频有黑边 直播拉流播放失败 直播拉流端卡顿现象 短视频上传失败 移动直播SDK对接第三方美颜库 移动直播连麦解决方案 Android移动直播推自定义采集的视频数据 Android移动直播推自定义采集的声音数据 Android直播播放如何获取YUV数据 Android直播播放如何自定义渲染 实时音视频画面黑屏 实时音视频订阅流显示 iOS 12默认新编译系统下文件名冲突问题 TXLiteAVSDK指标监控 进阶:小程序实时音视频参数透传 移动直播 Android 9.0 无法拉流问题 移动直播推流事件回调 移动直播拉流事件回调 短视频实现视频缩略图列表转GIF功能 roomService加入群组时报错invalid group id NTP时间戳转换 提示Role not exists 角色不存在 如何播放背景音乐 iOS端短视频添音频相关问题总结 Web同步终端离线推送TIMOfflinePushInfo说明文档 web端自定义消息发送 web端同步终端的已读回执 web端对群组内用户禁言操作 TRTC v2混流接口setMixTranscodingConfig使用指引

NTP时间戳转换

发布日期:2018年10月23日 更新日期:2018年10月23日 贡献者:zilongye

场景

腾讯视频云直播答题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;
}

示例

results matching ""

    No results matching ""