USB采集卡如何打pts

简介: USB采集卡如何打pts

一、使用采集卡提供的pts

二、手动打pts

1.usb采集设备pts的问题

2.采集卡驱动,UVC/UAC,ffmpeg的关系

3.如何自己打pts

4.音视频同步调优

5.NTP等联网调时工具带来的不同步问题


一、使用采集卡提供的pts


我们用使用pc摄像头和使用pc麦克风声卡里的方法,用ffmpeg采集后会得到音视频的pts。

我们应该尽量用好这些pts,因为他们的时间间隔很精准,比如48000,每次采集1024,发现每帧间隔21ms;视频采集1080p25,每帧间隔40ms。

使用之前我们需要把他们同步到同一个时间戳,其中一个方法是:

dif = 格林威治时间 - 第一帧采集到的视频时间戳

然后以后每次pts = pts + dif。

V:

AVDictionary *options = NULL;
av_dict_set(&options, “video_size”, “1920x1080”, 0);
av_dict_set(&options, “framerate”, “30”, 0);
//以上参数如果不设置的话,ffmpeg就会用默认值,但默认值摄像头不一定支持
int re = avformat_open_input(&ic, “/dev/video0”, ifmt, &options);


A:

av_dict_set(&options, "sample_rate", "48000", 0); // 只能是48000不支持改动
av_dict_set(&options, "channels", "2", 0);        // 无法改,不支持改动
long long GetCurTime()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    // ZlogInfo("second:%ld\n",tv.tv_sec);  //秒
    // ZlogInfo("millisecond:%ld\n",tv.tv_sec*1000 + tv.tv_usec/1000);  //毫秒
    // ZlogInfo("microsecond:%ld\n",tv.tv_sec*1000000 + tv.tv_usec);  //微秒
    long long temp_time = tv.tv_sec * 1000000 + tv.tv_usec;
    return temp_time;
}
if(this->dif_PTS == 0) this->dif_PTS = GetCurTime() - read_pkt.pts;
read_pkt.pts = read_pkt.pts + this->dif_PTS;


二、手动打pts

1.usb采集设备pts的问题

decklink的采集卡,会把音视频的pts给好,并且是可靠的。但小的厂商就不一定了。我这里使了一个台湾和国内的厂商,一个是pci采集卡(sdi/hdmi采集转pci口),这个采集卡支持UVC和UAC协议,另一个是usb(hdmi转usb口)采集卡。这两个价格都在千元左右。


跟这两个采集卡的原厂技术沟通,pts存在以下问题

1:音频和视频的pts没有关系,没有共同的起点或相关的联系。

2.pts经过一夜测试后发现,有跳变的现象。

3.采集1080p30时,视频的pts,每帧之间只增加20ms,而不是33ms,其他分辨率无此问题。

因为这些设备的用户大多数不是开发者,所以这些问题都不会用到,对于开发者来说则需要原厂定制开发了。


2.采集卡驱动,UVC/UAC,ffmpeg的关系


在与原厂电话微信后,对usb的采集卡有初步的了解,对于音频来说,采集卡的驱动并不会提供pts给系统,因为对于音频来说,确定好采样率,声道数,位深,那么在播放端,它的采样数对应的播放时间是固定的,采集卡只有一个晶振在控制着采集频率,音频从采集卡采集到其提供给系统,延时可以忽略。

视频采集卡的驱动也不会有pts,它的启动只会对上层提供类似于1,2,3…等视频的序号的标签,采集卡从采集到提供给系统,可能会有几帧,如4帧延时。

那么我们用ffmpeg采集到的音视频,都含有pts,那么这些pts是什么呢。音频是1970年开始到现在的us,视频则是开机的时间us。他们都是UVC和UAC协议对采集卡驱动提供的音视频帧打的pts。

因此数据的传输是这样的,采集卡->采集卡驱动->系统内核->UVC/UAC->ffmpeg

硬件厂商改一个问题,要改好几个版本,经常引入其他bug,看来天下程序员都一样。


3.如何自己打pts


那么我们该怎么自己打pts呢?

在两个线程里分别采集音视频:

av_read_frame()


我们把格林威治的PTS赋值给每次采集到的音视频数据。

A:

re = av_read_frame(ic_a, &read_pkt_a);   
read_pkt_a.pts = GetCurTime();


V:

re = av_read_frame(ic, &read_pkt);   
read_pkt.pts = GetCurTime();
ZlogInfo("dif:%ld\n", (shm_->GetCurTime() - LAST_PTS) / 1000);
LAST_PTS = shm_->GetCurTime();


视频每次从这个函数返回的时间间隔分别是:

//1080p25 39 40 39 40 39 40 39 40 39 40 39 40 ms

音频分别是:

//1080p25 41 0 42 0 42 0 41 0 41 0 42 0 ms

有时是

//1080p25 21 0 41 21 0 40 22 0 41 1 40 0 42 0 41 22 0 41 0 42 0 42 1 40 22 0 41 21 1 40


0并非没有间隔而是小于1ms,这里有精度损失。

可以看到间隔并不标准,因为av_read_frame()维护了一个缓存,他每次从采集卡拿到一阵或多帧音频或视频数据放入缓存,然后分包,返回一帧音频或视频数据,下次再调用直接去缓存里拿,如果缓存没有则阻塞住,直到采集卡提供了数据。


我们需要让他们的时间间隔相对均匀,那么每次的pts就和上次比较,如果少于一定时间则睡眠。

ZlogInfo("dif:%ld\n", (shm_->GetCurTime() - LAST_PTS) / 1000);
if((shm_->GetCurTime() - LAST_PTS) / 1000 < 10) usleep(10000);
pkt->pts = shm_->GetCurTime();
ZlogInfo("dif_last:%ld\n", (shm_->GetCurTime() - LAST_PTS) / 1000);
LAST_PTS = shm_->GetCurTime();


那么再次打印如下:

V:

//39 40 39 40 39 40 39 40 39 39 39 39 40 40

A:

//1080p25 31 12 30 10 32 10 31 11 31 10 32 11 30 10 32 10 32 10 30 10 31 11 31 10 31 10


4.音视频同步调优

因为采集视频到交给ffmpeg可能有几帧的缓存,因此每次的视频数据可以减去100ms左右,看看播出后的视频效果。

pkt->pts = shm_->GetCurTime() - 100000;


播放器的音视频同步策略一般都是按以音频为基准,音频是线性均匀的,那么音频的pts本身是没有意义的,两帧之间的间隔并不代表播放的时间间隔,它的意义主要是用于视频与他同步。

如果想要音频的间隔再均匀一些,可以调节以下睡眠的时间。


5.NTP等联网调时工具带来的不同步问题

pc每次开机联网后,系统自带NTP开始核对时间,并改变自身时间,那么你每次打的pts就会产生突变。NTP每次调剂的幅度可能在500ms左右,可以关闭它,或换小一点的工具,每次调解幅度在10ms左右的。


thxchtb3wcn3k_d11fc1ff3db9431d8ad7575e9297ae48.png

相关文章
|
传感器 定位技术 计算机视觉
树莓派开发笔记(九):基于CSI口的摄像头拍照程序(同样适用USB摄像头)
树莓派开发笔记(九):基于CSI口的摄像头拍照程序(同样适用USB摄像头)
树莓派开发笔记(九):基于CSI口的摄像头拍照程序(同样适用USB摄像头)
|
编解码 开发工具 Android开发
Android平台GB28181接入端如何对接UVC摄像头?
我们在对接Android平台GB28181接入的时候,有公司提出这样的需求,除了采集执法记录仪摄像头自带的数据外,还想通过执法记录仪采集外接UVC摄像头。
205 0
|
数据采集 索引
NI采集卡USB-6361多通道模拟输入采集报错解决方案
折腾一块 USB-6361 采集卡很久了,之前都是单通道采集模拟信号,突然接到要使用双通道采集模拟信号,本想着就新增加一路 Analog Input task 即可,但事情总没有想象的那么简单,因此记录一下解决的方法。
316 0
|
存储 编解码 算法
树莓派 之 USB摄像头 局域网内视频流实时传输( MJPG-Streamer)
树莓派 之 USB摄像头 局域网内视频流实时传输( MJPG-Streamer)
1400 0
树莓派 之 USB摄像头 局域网内视频流实时传输( MJPG-Streamer)
可编程 USB 转串口适配器开发板参数设置
前述各种指令在参数修改完成后仅可当时生效,修改后的参数断电不保存。使用[SAVE]关键字可将当前参数保存至 EEPROM,使参数永久保存。
可编程 USB 转串口适配器开发板参数设置
可编程 USB 转串口适配器开发板 USB 转 UART和 I2C
USB2S 内置了 USB 转UART 芯片,可使用CH340/CH341 驱动程序。驱动安装步骤如下: 双击运行“CH341SER\SETUP.exe”,打开驱动安装窗口。
可编程 USB 转串口适配器开发板 USB 转 UART和 I2C
|
芯片
单路USB转多路串口方案分享
单路USB转多路串口方案分享
416 0
单路USB转多路串口方案分享
|
传感器 芯片
可编程 USB 转串口适配器开发板 SHT3x-DIS 温湿度传感器芯片
SHT3x-DIS 是 IIC 接口的温度、湿度传感器芯片,可工作于单次测量或连续自动测量模式。USB2S 已有 1 片 SHT31-DIS 芯片,芯片地址为 0x88。 SHT3X-DIS 的输出温度和湿度均为 3 字节,前两字节是温湿度值,第 3 字节是校验字节。转换 公式如下:(数值=第 1 个字节*256+第 2 个字节)。
可编程 USB 转串口适配器开发板  SHT3x-DIS 温湿度传感器芯片
|
存储 芯片
可编程 USB 转串口适配器开发板 USB 转 UART I2C 应用
USB 转UART 原理 驱动程序安装后,计算机通过 COMx 与 MCU 进行通讯,当 USB2S 的 UART 透明传输功能为开启状态时(默认),MCU 可将 UART1 与UART2 的双向数据进行透明转发,即:实现了计算机的COMx 端口与 USB2S 的对外 UART2 端口的双向数据传输。
可编程 USB 转串口适配器开发板 USB 转 UART  I2C 应用
|
存储 传感器 编解码
Blackfly S USB3工业相机:缓冲区处理
Blackfly S 采用业内先进的冰块外形传感器。 具有强大功能,可以轻松生成所需的精确图像,并加速应用程序开发。 包括对图像捕获和相机预处理的自动和精确手动控制。 Blackfly S 提供GigE、USB3、套装和板级版本。 精确图像 索尼CMOS传感器中的选择包括:全局快门、偏振和高灵敏度BSI传感器。
Blackfly S USB3工业相机:缓冲区处理