ts demuxer的加入记录

文件夹

1 初衷

2 ts demux的功能介绍

1 初衷



之前打算给dtplayer加入一些亮点功能,最初的想法是:bt下载播放 + hls支持

bt下载因为以来libtorrent库,尽管搞懂了怎样加入,但须要改动libtorrent库来集成,

若将libtorrent集成到代码中,会将代码变得庞大,框架清晰度会变差,随机临时取消了bt功能的开发/

后面開始加入hls支持,hls支持打算加入例如以下模块: stream - hls   demuxer - ts  decoder - h264 这样加上之前的faad

对于特定网络流就能够不依赖ffmpeg来播放了。

ts demuxer便是第一步功能。

凭借之前对ts的理解,感觉应该比較快完毕的,当时从github中找到了一个开源的ts解析库:https://github.com/nevali/tsdemux

但不幸的是这个库仅仅提供了 section的解析功能,并没有提供读取es包的功能。遂打算自行将这部分功能补全。

代码: https://github.com/peterfuture/dtplayer/blob/dev-ts/dtdemux/demuxer/demuxer_ts.c

2 ts demux的功能

ts demux符合dtplayer demuxer的标准接口,

先看下定义:


demuxer_wrapper_t demuxer_ts = {

.name = "ts demuxer",

.id = DEMUXER_TS,

.probe = ts_probe,

.open = ts_open,

.read_frame = ts_read_frame,

.setup_info = ts_setup_info,

.seek_frame = ts_seek_frame,

.close = ts_close

};

以下依次介绍各个功能。

2.1 probe


static int ts_probe(demuxer_wrapper_t *wrapper, dt_buffer_t *probe_buf)

{

const uint8_t *buf = probe_buf->data;

const uint8_t *end = buf + probe_buf->level - 7;

if(probe_buf->level < 10)

return 0;

int retry_times = 100;

for(; buf < end; buf++)

{

uint32_t header = DT_RB8(buf);

if((header&0xFF) != 0x47)

{

if(retry_times-- == 0)

return 0;

continue;

}

//found 0x47

if(buf+188 > end)

return 0;

header = DT_RB8(buf+188);

if((header & 0xFF) == 0x47)

{

dt_info(TAG,"ts detect \n");

return 1;

}

else

return 0;

}

return 0;

}

这里实现了一个比較简单的probe功能,先找到同步字0x47,若后面188字节后面也是0x47,则觉得是ts流,临时probe有些流还不能解析

主要问题有: a 有些流的包大小并非188, 这样的流会出错 b 单纯的仅仅推断一次会有偶然性的问题

但这些修正起来比較简单,因为功能还未实现,这里仅仅介绍思想,还有面会完好

2 ts_open

这里是解析ts头信息,主要功能包含:

pat解析

pmt解析

stream 信息解析: duration - bitrate

es信息解析:audio: channel-samplerate-bps  video: width-height-fmt

这里代码比較多就仅仅说下思想,感兴趣的自己去读代码就能够了

首先pat pmt的解析是通过之前说的开源库完毕的,通过解析pat pmt能够得到文件里有几个流,各自是什么格式

得到后一般若有video stream,则以video为參考来计算流信息(正确的做法是找到流的pcr_pid,也就是參考流来计算,但普通情况下參考流都是video)

计算duration: 首先找到第一帧的pts , 然后找到最后一帧的pts, 通过pts差距得到duration

计算bitrate: 有了stream size和 duration, 直接计算得到bitrate

当中计算pts的时候,这里介绍下,详细代码在ts/stream.c中,是后面我自己加的

if(packet->payloadlen > 0 && packet->unitstart)

{

uint8_t *pcrbuf = packet->payload;

int len = pcrbuf[0];

if(len <= 0 || len > 183)	//broken from the stream layer or invalid

goto QUIT;

pcrbuf++;

int flags = pcrbuf[0];

int has_pcr;

has_pcr = flags & 0x10;

pcrbuf++;

if(!has_pcr)

goto QUIT;

int64_t pcr = -1;

int64_t pcr_ext = -1;

unsigned int v = 0;

//v = (uint32_t)pcrbuf[3]<<24 | pcrbuf[2]<<16 |	pcrbuf[1]<<8 |pcrbuf[0];

v = (uint32_t)pcrbuf[0]<<24 | pcrbuf[1]<<16 |	pcrbuf[2]<<8 |pcrbuf[3];

pcr = ((int64_t)v<<1) | (pcrbuf[4] >> 7);

pcr_ext = (pcrbuf[4] & 0x01) << 8;

pcr_ext |= pcrbuf[5];

pcr = pcr * 300 + pcr_ext

packet->pts = pcr / 300;

//printf("get pts:%lld \n",pcr);

}

这里是去掉了ts包开头的四个字节,首先看是否是一帧的开头,若是的话推断是否有pcr flag

若有则直接解析,解析方法比較简单,依照标准就可以

这里介绍下ts的编码參考时钟为:27M HZ,而pts的单位与时间s的换算为:90000

因此获取參考时间(也就是上面的pcr后),换算为pts的计算方式为: pts = pcr * 9000 / 27000000 = pcr / 300

这里得到的就直接是pts了。

另一个问题是:这里直接解析es流貌似不能获取 视频: width height  音频:channel samplerate等信息,

对于ffmpeg来讲没有问题,因此在av_find_stream_info中能够通过decode one frame来获取, 但dtplayer框架上是不方便直接启动解码器的

对于mplayer 的ts 也是没有decode的,知道的同学能够指导下最好,不胜感激,否则得自己扒mplayer的代码了。

3 ts_setup_info

这里根据ts_open获取的信息,来setup dtplayer的media info

然后选择av视频流就能够了,比較简单

4 ts_read_frame

这里比較重要,也是花了比較多时间的地方,一開始的时候,以为拿到av的pid后,后面直接组装数据就能够了

流程为: 解析ts包获取pid -> 若是选择的pid,直接将payload保存下来,通过简单的推断是否是unit_start来推断是否读取到了完整帧 --> 返回完整帧

但实际情况并非这样,保存在ts包中的是实际的pes包,而不是es流,在读包的时候须要将pes包头去掉

这里參考ffmpeg进行了模拟,详细代码在:handle_ts_pkt中,详细逻辑不说了,仅仅是更正自己的一个认知误区

只是这里还有个问题,读取的数据包会掺杂错误信息: 经过跟代码,大体定位了问题,在解析pes包头的时候,是能够知道这个包的大小的

但读取ts包的时候都是依照188,即payload通常是184字节,这样非常有可能就超过了pes包的大小

此时应该怎样处理: 若仅仅读取固定大小凑足包大小返回,则声音是错的

若将全部payload都打包进去,则播放过程会有杂音。

这里还须要研究下。有熟悉的同学也请指教

5 ts_seek

这里seek就比較简单了,尽管还未完毕,但思想能够说下,參考ffmpeg,一句bitrate seek到某个位置,读取ts包,计算pts

若不匹配,则依照二分查找算法,继续seek

来达到seek的目的。(后面会实现)

这里ts demux仅仅是为了实现一个简单的功能,给后面基于dtplayer开发简单的应用的开发人员提供便利: 若服务端也自己做的话,能够非常方便的改造dtplayer中的ts demux达到字节的要求,

同一时候去掉了ffmpeg的负担,岂不非常方便,这也是dtplayer会一直遵循的目标。

github:https://github.com/avplayer/dtplayer   # C++

github:https://github.com/peterfuture/dtplayer # C

bug report: [email protected]

blog: http://blog.csdn.net/dtplayer

bbs: http://avboost.com/

wiki: http://wiki.avplayer.org/Dtplayer

因为后面随着开发的进行文章会进行细节的更新,因此为了保证读者随时读到最新的内容,文章禁止转载,多谢大家支持!

时间: 2024-10-12 18:03:34

ts demuxer的加入记录的相关文章

nodejs项目升级为ts

前言 最近把之前自用的一个小型nodejs框架(koa2+mongo)升级为了ts,在此记录一下大致步骤. 安装typescript 直接使用npm 安装 npm i -S -D typescript 建议不要只安装到全局,避免不同机器上的typescript版本不一致. 安装完之后,我们新建一个tsconfig.json(或者tsc init),这是我的内容: { "compilerOptions": { // "incremental": true, /* 增量

Mysql基准测试详细解说(根据慕课网:《打造扛得住Mysql数据库架构》视频课程实时笔录)

什么是基准测试 基准测试是一种测量和评估软件性能指标的活动用于建立某个时刻的性能基准,以便当系统发生软硬件变化时重新进行基准测试以及评估变化对性能的影响. 我们可以这样认为:基准测试是针对系统设置的一种压力测试.用来观察系统在不同压力下的行为,评估系统的容量,观察系统如何处理不同的数据,但是要注意的是基准测试和通常所说的压力测试还是有区别的. 基准测试要尽量的直接和简单,使各个结果之间容易比较,基准测试所使用的数据通常是由测试工具所生成的,只能用于评估服务器的 处理能力:而压力测试通常是通过真实

MpegTS流解复用程序实现(解复用得到PES和ES)

MpegTS基础看这几篇博文: MpegTS基础 MpegTS之TS,PES,ES结构分析 TS流复用和解复用是一个相逆的过程.TS解复用得到的是音视频的PES裸流.一般来讲,每个TS包的长度是188个字节,也有一种204个字节的,就是在每个包后面加上16个字节的RS冗余校验信息.在这里分析188个字节的情况,其余的都类似了. 从文件中循环读取188个字节的包,然后对包进行逐字节分析,分析流程如下: TS包的标志是首字节以0x47开头 如下图是一个ts包: 按位解析,得到pid,flag,错误标

typescript-koa-postgresql 实现一个简单的rest风格服务器 —— typescript 开发环境配置

最近需要用 nodeJS 写一个后台程序,为了能够获得 IDE 的更多代码提示,决定用 typescript 来编写,随便也学习下 ts,在这记录下实现过程. 1.新建文件夹 typescript-koa-postgresql,初始化项目 yarn init -y 2.安装 typescript yarn add typescript @types/node --dev 3.配置  typescript 编译环境,在项目根目录下新建文件 tsconfig.json 1 { 2 "compiler

BFS/DFS 广度/深度优先搜索

深度优先搜索DFS 所谓深度优先搜索,通俗点理解就是一条路走到头--不撞南墙不回头. 我们先来看一个全排列问题,现在要对1 2 3进行全排列,现在小哼手上拿着1 2 3三张卡片,他要将这三张卡片放入三个盒子里,每放满不就是一种全排列了么? 但是每次到底是先放卡片1还是卡片2,3呢? 小哼想,我按顺序放吧,每次都按照1.2.3的顺序放卡片.于是他走到1号盒子前把卡片1放入,走到2号盒子前把卡片2放入,走到3号盒子前把卡片3放入,走到四号盒子...但小哼的卡片已经放完 啦.这时就产生了一种全排列"1

关于MySQL的基准测试

什么是基准测试 当我们对数据库进行优化后,只有进行测量系统性能才能知道优化是否有效,这种测量的方式就是基准测试.基准测试的定义如下: 基准测试是一种测量和评估软件性能指标的活动用于建立某个时刻的性能基准,以便当系统发生软/硬件变化时,重新进行基准测试以评估变化对性能的影响 我们可以这样认为: 基准测试是针对系统设置的一种压力测试,可以用来观察系统在不同压力下的行为.评估系统的容量,观察系统如何处理不同的数据. 但是基于测试不等同于压力测试: 基于测试:直接.简单.易于比较,用于评估服务器的处理能

在 Vue 中使用 Typescript

前言 恕我直言,用 Typescript 写 Vue 真的很难受,Vue 对 ts 的支持一般,如非万不得已还是别在 Vue 里边用吧,不过听说 Vue3 会增强对 ts 的支持,正式登场之前还是期待一下吧嘻嘻. 本篇不会过多讲述 ts 语法,着重记录下 在 Vue 中使用 ts 的方法以及踩坑经过. 如果是使用 Vue Cli2 搭建的项目,要注意 webpack 版本可能与 ts-loader 版本不匹配,可以降低 ts-loader 版本到 3.0+ 或者 将 webpack升级到 4.0

python小白学习记录 多线程爬取ts片段

from lxml import etree import requests from urllib import request import time import os from queue import Queue import threading import re from multiprocessing import pool from urllib import request def download(urls): for index in range(0,1342): n =

最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)

打算记录一下基于FFmpeg的封装格式处理方面的例子.包括了视音频分离,复用,封装格式转换.这是第2篇. 本文记录一个基于FFmpeg的视音频分离器(Simplest FFmpeg demuxer).视音频分离器(Demuxer)即是将封装格式数据(例如MKV)中的视频压缩数据(例如H.264)和音频压缩数据(例如AAC)分离开.如图所示.在这个过程中并不涉及到编码和解码. 本文记录的程序可以将一个MPEG2TS封装的视频文件(其中视频编码为H.264,音频编码为AAC)分离成为两个文件:一个H