1. 简介
在本篇文章中, 我会详细的记录我学习MPEG2TSExtractor
的全部过程. 与其说是一篇技术博客, 不如说是一篇学习笔记吧. 纯属爱好而已. 万事开头难, 那我们就先从“它是怎么来滴”入手把。
2. 从"MPEG2TSExtractor出生"开始
按照惯例, 我们从构造函数看起.
115 MPEG2TSExtractor::MPEG2TSExtractor(const sp &source)
116 : mDataSource(source),
117 mParser(new ATSParser),
118 mLastSyncEvent(0),
119 mOffset(0) {
120 init();
121 }
- 将DataSource传进来(DataSource就是文件源);
- 然后创建一个ATSParse, 这个类是负责具体来parse数据的;
- mLastSyncEvent初始化为0, 他是干嘛的? 看看官方解释:
62 // Used to remember SyncEvent occurred in feedMore() when called from init(),
63 // because init() needs to update |mSourceImpls| before adding SyncPoint.
我想应该是用来用于seek的吧.
- 接着是mOffset初始化为0, 他代表着当前读取文件源的偏移量;
- 调用
init()
, 进行初始化.
2.1 MPEG2TSExtractor::init()
init()
方法多达180多行, 这着实让小弟十分为难, 肿么办呢, 嫌麻烦的童鞋就直接看代码下方小弟的个人见解吧.
183 void MPEG2TSExtractor::init() {
184 bool haveAudio = false;
185 bool haveVideo = false;
186 int64_t startTime = ALooper::GetNowUs();
187
188 status_t err;
189 while ((err = feedMore(true /* isInit */)) == OK
190 || err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
191 if (haveAudio && haveVideo) {
192 addSyncPoint_l(mLastSyncEvent);
193 mLastSyncEvent.reset();
194 break;
195 }
196 if (!haveVideo) {
197 sp impl =
198 (AnotherPacketSource *)mParser->getSource(
199 ATSParser::VIDEO).get();
200
201 if (impl != NULL) {
202 sp format = impl->getFormat();
203 if (format != NULL) {
204 haveVideo = true;
205 addSource(impl);
206 if (!isScrambledFormat(format)) {
207 mSyncPoints.push();
208 mSeekSyncPoints = &mSyncPoints.editTop();
209 }
210 }
211 }
212 }
213
214 if (!haveAudio) {
215 sp impl =
216 (AnotherPacketSource *)mParser->getSource(
217 ATSParser::AUDIO).get();
218
219 if (impl != NULL) {
220 sp format = impl->getFormat();
221 if (format != NULL) {
222 haveAudio = true;
223 addSource(impl);
224 if (!isScrambledFormat(format)) {
225 mSyncPoints.push();
226 if (!haveVideo) {
227 mSeekSyncPoints = &mSyncPoints.editTop();
228 }
229 }
230 }
231 }
232 }
233
234 addSyncPoint_l(mLastSyncEvent);
235 mLastSyncEvent.reset();
236
237 // ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED is returned when the mpeg2ts
238 // is scrambled but we don't have a MediaCas object set. The extraction
239 // will only continue when setMediaCas() is called successfully.
240 if (err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
241 ALOGI("stopped parsing scrambled content, "
242 "haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
243 haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
244 return;
245 }
246
247 // Wait only for 2 seconds to detect audio/video streams.
248 if (ALooper::GetNowUs() - startTime > 2000000ll) {
249 break;
250 }
251 }
252
253 off64_t size;
254 if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) {
255 sp impl = haveVideo
256 ? (AnotherPacketSource *)mParser->getSource(
257 ATSParser::VIDEO).get()
258 : (AnotherPacketSource *)mParser->getSource(
259 ATSParser::AUDIO).get();
260 size_t prevSyncSize = 1;
261 int64_t durationUs = -1;
262 List durations;
263 // Estimate duration --- stabilize until you get <500ms deviation.
264 while (feedMore() == OK
265 && ALooper::GetNowUs() - startTime <= 2000000ll) {
266 if (mSeekSyncPoints->size() > prevSyncSize) {
267 prevSyncSize = mSeekSyncPoints->size();
268 int64_t diffUs = mSeekSyncPoints->keyAt(prevSyncSize - 1)
269 - mSeekSyncPoints->keyAt(0);
270 off64_t diffOffset = mSeekSyncPoints->valueAt(prevSyncSize - 1)
271 - mSeekSyncPoints->valueAt(0);
272 int64_t currentDurationUs = size * diffUs / diffOffset;
273 durations.push_back(currentDurationUs);
274 if (durations.size() > 5) {
275 durations.erase(durations.begin());
276 int64_t min = *durations.begin();
277 int64_t max = *durations.begin();
278 for (auto duration : durations) {
279 if (min > duration) {
280 min = duration;
281 }
282 if (max < duration) {
283 max = duration;
284 }
285 }
286 if (max - min < 500 * 1000) {
287 durationUs = currentDurationUs;
288 break;
289 }
290 }
291 }
292 }
293 status_t err;
294 int64_t bufferedDurationUs;
295 bufferedDurationUs = impl->getBufferedDurationUs(&err);
296 if (err == ERROR_END_OF_STREAM) {
297 durationUs = bufferedDurationUs;
298 }
299 if (durationUs > 0) {
300 const sp meta = impl->getFormat();
301 meta->setInt64(kKeyDuration, durationUs);
302 impl->setFormat(meta);
303 } else {
304 estimateDurationsFromTimesUsAtEnd();
305 }
306 }
307
308 ALOGI("haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
309 haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
310 }
184 - 185: 初始化haveAudio
和haveVideo
为false
. 为什么要这样做呢? 原来接下来会去使用feedMore
去读取DataSource
文件源中的数据到AnotherPacketSource
中, 这两个标志位就是标识A/V Track中是否有读到数据的.
189 - 251: 循环的去读取数据直至①feedMore return != OK
或者②时间到了2s
或者③有A&V数据了
, 就退出循环.(另外一个和DRM有关, 我们在这里暂且不管)
- 191 - 195: 如果已经读取过数据了, 直接将
SyncEvnet
加入其中, 然后reset
, 退出循环; - 196 - 212: 使用
ATSParse
的getSource
去获取Video数据到impl
中, 并addSource
去Vector
中去寻找, 如果找到了就啥事不做, 如果没有找到就加入到这个Vector当中去;mSourceImpl - 214 - 230: 同上, 是对audio数据进行的操作;
- 248 - 250: 对时间进行控制, 也就是说这个while循环不能执行超过2s. (如果init超过了2s, 我相信体验一定会像这行号一样, 很250吧_);
263 - 306: 简单的说是用两种方式去计算播放的Duration.
- 264 - 292: 通过计算从
feedMore
方法中, 加入的SyncEvent点的最后点
-第一点
来计算duration
. 然后将这些duration放在一起比较, 当最近的5个duration相差在500ms内的时候, 就算计算完成了; (这是一种) - 293 - 306: 通过
getBufferedDurationUs
或者estimateDurationsFromTimesUsAtEnd
来估算Duration
.
2.2 MPEG2TSExtractor::feedMore()
feedMore, 以我的英语水平, 我解释为"吃更多"(偷笑~). 看看他吃了些什么东东.
312 status_t MPEG2TSExtractor::feedMore(bool isInit) {
313 Mutex::Autolock autoLock(mLock);
314
315 uint8_t packet[kTSPacketSize];
316 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
317
318 if (n < (ssize_t)kTSPacketSize) {
319 if (n >= 0) {
320 mParser->signalEOS(ERROR_END_OF_STREAM);
321 }
322 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
323 }
324
325 ATSParser::SyncEvent event(mOffset);
326 mOffset += n;
327 status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
328 if (event.hasReturnedData()) {
329 if (isInit) {
330 mLastSyncEvent = event;
331 } else {
332 addSyncPoint_l(event);
333 }
334 }
335 return err;
336 }
315 - 316: 去DataSource
里面读取188个Byte的数据到packet
里面;
318 - 323: 判断一下是否eos;
327 : 关键点: 去ATSParser里, 使用feedTSPacket(喂养TS包去咯~).
328 - 334: 根据isInit
的状态, 更新下SynvEvent.
3. "ATSParse"闪亮登场
经过漫长的等待, 我们的ATSParser
终于登场了.这位大佬的工作就是专门用来parse program
以及其内的stream
的. 好的, 让我们来看看他的构造函数:
3.1 ATSParser::ATSParser(uint32_t flags)
1616 ATSParser::ATSParser(uint32_t flags)
1617 : mFlags(flags),
1618 mAbsoluteTimeAnchorUs(-1ll),
1619 mTimeOffsetValid(false),
1620 mTimeOffsetUs(0ll),
1621 mLastRecoveredPTS(-1ll),
1622 mNumTSPacketsParsed(0),
1623 mNumPCRs(0) {
1624 mPSISections.add(0 /* PID */, new PSISection);
1625 mCasManager = new CasManager();
1626 }
1617 - 1623: 简单的对一些标志位, 以及时间戳的标识进行赋值;
1624: 关键点, 将new
一个pid = 0
的PSISection
, 并加入mPSISections
. 这个在后来的流程中有大作用. 现在暂且不表.(表打我);
1625: new
一个CasManager
. 这个是干嘛的? 之后在关注. 先看主要流程;
3.2 status_t ATSParser::feedTSPacket(const void *data, size_t size, SyncEvent *event)
我们来看看是肿么"喂养"TSPacket
的吧.
1631 status_t ATSParser::feedTSPacket(const void *data, size_t size,
1632 SyncEvent *event) {
1633 if (size != kTSPacketSize) {
1634 ALOGE("Wrong TS packet size");
1635 return BAD_VALUE;
1636 }
1637
1638 ABitReader br((const uint8_t *)data, kTSPacketSize);
1639 return parseTS(&br, event);
1640 }
1633 - 1636: 判断下kTSPacketSize
的大小;
1638: 初试化一个ABitReader br
去读取这个容量为188的TS packet;
1639: 走进parseTS
;
3.3 status_t ATSParser::parseTS(ABitReader *br, SyncEvent *event)
在正式展开parse TS包工作之前, 我建议再回顾下TS包的组织结构. 在这里, 我就引用其他大神画的图了.TS流格头部如图所示:
在了解了TS头部是如何组织起来的后, 我们来看看具体是如何完成
parseTS
工作的, 代码如下所示:
1950 status_t ATSParser::parseTS(ABitReader *br, SyncEvent *event) {
1951 ALOGV("---------------------start parse TS-----------------------");
1952
1953 unsigned sync_byte = br->getBits(8);
1954 if (sync_byte != 0x47u) {
1955 ALOGE("[error] parseTS: return error as sync_byte=0x%x", sync_byte);
1956 return BAD_VALUE;
1957 }
1958
1959 if (br->getBits(1)) { // transport_error_indicator
1960 // silently ignore.
1961 return OK;
1962 }
1963
1964 unsigned payload_unit_start_indicator = br->getBits(1);
1965 ALOGV("payload_unit_start_indicator = %u", payload_unit_start_indicator);
1966
1967 MY_LOGV("transport_priority = %u", br->getBits(1));
1968
1969 unsigned PID = br->getBits(13);
1970 ALOGV("PID = 0x%04x", PID);
1971
1972 unsigned transport_scrambling_control = br->getBits(2);
1973 ALOGV("transport_scrambling_control = %u", transport_scrambling_control);
1974
1975 unsigned adaptation_field_control = br->getBits(2);
1976 ALOGV("adaptation_field_control = %u", adaptation_field_control);
1977
1978 unsigned continuity_counter = br->getBits(4);
1979 ALOGV("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter);
1980
1981 // ALOGI("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter);
1982
1983 status_t err = OK;
1984
1985 unsigned random_access_indicator = 0;
1986 if (adaptation_field_control == 2 || adaptation_field_control == 3) {
1987 err = parseAdaptationField(br, PID, &random_access_indicator);
1988 }
1989 if (err == OK) {
1990 if (adaptation_field_control == 1 || adaptation_field_control == 3) {
1991 err = parsePID(br, PID, continuity_counter,
1992 payload_unit_start_indicator,
1993 transport_scrambling_control,
1994 random_access_indicator,
1995 event);
1996 }
1997 }
1998
1999 ++mNumTSPacketsParsed;
2000
2001 return err;
2002 }
1953 - 1957: 读取8bit, 看下是否是0x47
;
1959 - 1962: 如果传输错误, 返回OK. (想了一下, 这样做的后果是, 虽然上面就收到OK, 但是AnohterPacketSource
依然是拿不到ABuffer
数据的, 所以会继续执行feedMore
);
1964 - 1695: parload 起始指示符;
1969 - 1970: 读取13bit, 拿到PID
. 这波操作很关键. 这个PID
唯一的标识着这个包, 我们可以通过判断PID的值, 获取到这一包TS是什么数据包含其中. 具体的, 下文将具体展开. 这里, 我们只看下PID代表哪些包;
PID取值 | PID值使用描述 |
---|---|
0x0000 | 节目关联表(program association table, PAT) |
0x0001 | 条件访问表(conditional access table, CAT) |
0x0002 | 传送流描述表(transport stream description table, TSDT) |
0x0003~0x000F | 保留 |
0x0010~0x1FFE | 可以分配为network PID, Program map PID, elementary PID, 或其它 |
0x1FFF | 空包(8191) |
1972 - 1973: 读取2bit, 标识传输过程中是否加扰;
1975 - 1976: 读取2bit, 标识自适应段控制. 那具体怎么个控制法, 我们来看一张表格;
调整字段值 | 十进制 | 描述 |
---|---|---|
00 | 0 | 保留 |
01 | 1 | 没有调整字段,仅含有184B长度的有效净荷 |
10 | 2 | 没有有效净荷,仅含有183B长度的调整字段 |
11 | 3 | 0~182B的调整字段后为有效净荷 |
从表格中, 我们很容易知道两点信息. ①前1个bit, 1
代表有调整字段, 反之则没有; ②后1个bit, 1
代表有available payload. 这里的信息, 对于接下来的parse 工作是十分重要的.
1978 - 1979: 读取4bit, 标识连续计数器(0 - f, 如果超过f, 则从0开始继续计数);
1986 - 1988: 如果是没有有效净荷,仅含有183B长度的调整字段
||
0~182B的调整字段后为有效净荷
, 也就是说, 这个TS packet中有自适应字段, 那么我们调用parseAdaptationField
, 搞搞自适应字段的parse工作;
1990 - 1997: 如果没有出错(err = OK
), 那么如果1, 3(有available payload
), 我们就开始针对PID
parse数据啦.在此调用的是parsePID
;
1999 - 2001: parse的TS packet数量自增, 然后返回parse的结果err
.
接下来, 我们就来看看parseAdaptationField
和parsePID
吧.
3.4 status_t ATSParser::parseAdaptationField
1880 status_t ATSParser::parseAdaptationField(
1881 ABitReader *br, unsigned PID, unsigned *random_access_indicator) {
1882 *random_access_indicator = 0;
1883 unsigned adaptation_field_length = br->getBits(8);
1884
1885 if (adaptation_field_length > 0) {
1886 if (adaptation_field_length * 8 > br->numBitsLeft()) {
1887 ALOGV("Adaptation field should be included in a single TS packet.");
1888 return ERROR_MALFORMED;
1889 }
1890
1891 unsigned discontinuity_indicator = br->getBits(1);
1892
1893 if (discontinuity_indicator) {
1894 ALOGV("PID 0x%04x: discontinuity_indicator = 1 (!!!)", PID);
1895 }
1896
1897 *random_access_indicator = br->getBits(1);
1898 if (*random_access_indicator) {
1899 ALOGV("PID 0x%04x: random_access_indicator = 1", PID);
1900 }
1901
1902 unsigned elementary_stream_priority_indicator = br->getBits(1);
1903 if (elementary_stream_priority_indicator) {
1904 ALOGV("PID 0x%04x: elementary_stream_priority_indicator = 1", PID);
1905 }
1906
1907 unsigned PCR_flag = br->getBits(1);
1908
1909 size_t numBitsRead = 4;
1910
1911 if (PCR_flag) {
1912 if (adaptation_field_length * 8 < 52) {
1913 return ERROR_MALFORMED;
1914 }
1915 br->skipBits(4);
1916 uint64_t PCR_base = br->getBits(32);
1917 PCR_base = (PCR_base << 1) | br->getBits(1);
1918
1919 br->skipBits(6);
1920 unsigned PCR_ext = br->getBits(9);
1921
1922 // The number of bytes from the start of the current
1923 // MPEG2 transport stream packet up and including
1924 // the final byte of this PCR_ext field.
1925 size_t byteOffsetFromStartOfTSPacket =
1926 (188 - br->numBitsLeft() / 8);
1927
1928 uint64_t PCR = PCR_base * 300 + PCR_ext;
1929
1930 ALOGV("PID 0x%04x: PCR = 0x%016" PRIx64 " (%.2f)",
1931 PID, PCR, PCR / 27E6);
1932
1933 // The number of bytes received by this parser up to and
1934 // including the final byte of this PCR_ext field.
1935 uint64_t byteOffsetFromStart =
1936 uint64_t(mNumTSPacketsParsed) * 188 + byteOffsetFromStartOfTSPacket;
1937 //按照PID去更新PCR信息
1938 for (size_t i = 0; i < mPrograms.size(); ++i) {
1939 updatePCR(PID, PCR, byteOffsetFromStart);
1940 }
1941
1942 numBitsRead += 52;
1943 }
1944 //把剩下的无用的bit位跳过处理;
1945 br->skipBits(adaptation_field_length * 8 - numBitsRead);
1946 }
1947 return OK;
1948 }
1883: 读取8bit, 获取自适应字段长度;
1885 - 1889: 如果长度>剩下的长度, 返回ERROR_MALFORMED
;
1891: 读取1bit, 非连续指示符;
1897: 读取1bit, 随机读取指示符;
1902: 读取1bit, 基本流优先级指示符;
1907: PCR
标志;
1911 - 1946: 处理PCR相关事宜, 小弟关于此部分还没有研究, 暂且跳过;
3.5 status_t ATSParser::parsePID
代码是在太长了, 不知各位客官是否还记得, 在parseAdaptationField
后, 如果err == OK
, 那么我们继续进行parsePID
的工作.
1778 status_t ATSParser::parsePID(
1779 ABitReader *br, unsigned PID,
1780 unsigned continuity_counter,
1781 unsigned payload_unit_start_indicator,
1782 unsigned transport_scrambling_control,
1783 unsigned random_access_indicator,
1784 SyncEvent *event) {
1785 ssize_t sectionIndex = mPSISections.indexOfKey(PID);
1786
1787 if (sectionIndex >= 0) {
1788 sp section = mPSISections.valueAt(sectionIndex);
1789
1790 if (payload_unit_start_indicator) {
1791 if (!section->isEmpty()) {
1792 ALOGW("parsePID encounters payload_unit_start_indicator when section is not empty");
1793 section->clear();
1794 }
1795
1796 unsigned skip = br->getBits(8);
1797 section->setSkipBytes(skip + 1); // skip filler bytes + pointer field itself
1798 br->skipBits(skip * 8);
1799 }
1800
1801 if (br->numBitsLeft() % 8 != 0) {
1802 return ERROR_MALFORMED;
1803 }
1804 status_t err = section->append(br->data(), br->numBitsLeft() / 8);
1805
1806 if (err != OK) {
1807 return err;
1808 }
1809
1810 if (!section->isComplete()) {
1811 return OK;
1812 }
1813
1814 if (!section->isCRCOkay()) {
1815 return BAD_VALUE;
1816 }
1817 ABitReader sectionBits(section->data(), section->size());
1818
1819 if (PID == 0) {
1820 parseProgramAssociationTable(§ionBits);
1821 } else {
1822 bool handled = false;
1823 for (size_t i = 0; i < mPrograms.size(); ++i) {
1824 status_t err;
1825 if (!mPrograms.editItemAt(i)->parsePSISection(
1826 PID, §ionBits, &err)) {
1827 continue;
1828 }
1829
1830 if (err != OK) {
1831 return err;
1832 }
1833
1834 handled = true;
1835 break;
1836 }
1837
1838 if (!handled) {
1839 mPSISections.removeItem(PID);
1840 section.clear();
1841 }
1842 }
1843
1844 if (section != NULL) {
1845 section->clear();
1846 }
1847
1848 return OK;
1849 }
1850
1851 bool handled = false;
1852 for (size_t i = 0; i < mPrograms.size(); ++i) {
1853 status_t err;
1854 if (mPrograms.editItemAt(i)->parsePID(
1855 PID, continuity_counter,
1856 payload_unit_start_indicator,
1857 transport_scrambling_control,
1858 random_access_indicator,
1859 br, &err, event)) {
1860 if (err != OK) {
1861 return err;
1862 }
1863
1864 handled = true;
1865 break;
1866 }
1867 }
1868
1869 if (!handled) {
1870 handled = mCasManager->parsePID(br, PID);
1871 }
1872
1873 if (!handled) {
1874 ALOGV("PID 0x%04x not handled.", PID);
1875 }
1876
1877 return OK;
1878 }
首先, 我们去获取到PSISection的index. 继而操作这个PSISection(Program Special Information).不知各位看官是否还记得, 在3.3 parseTS中, 我们有提到MPEG2 TS传输的TS包, 携带两类信息: ①已压缩的A/V(PES)和②与之相关的符号化表(PSI). 这些信息都是通过PID来区别的.
我们在parse的工作中, 要首先去解析PSI所携带的信息, 然后根据或者的信息, 去解析PES信息.好了, 我们来看看代码实现.
1785: 获取PSISection的index(PSISection被组织在一个KeyedVector
中, Key为PID
, Value为sp
);
1787 - 1849: 如果index >= 0
, 我们就开始进行parse PSI的工作啦.(在ATSParse构造函数中, 我们mPSISections.add(0 /* PID */, new PSISection);
. 可见, 如果是在init
过程中, 这个index = 0
).
1790 - 1799: 如果
payload_unit_start_indicator = 1
, 表示TS包带有PSI部分的第一个字节,即第一个字节带有指针pointer_field. 所以我们要跳过skip + pointer_field指针所占的8个bit;1801 - 1803: 如果剩下的bit数不是8的倍数, 返回不符合;
1804: 将剩下的bit位append到PSISection管理的Data中;
1817:
new
一个sectionBits
, 准备开始读取bit位.1819 - 1820: 重点: 如果
PID == 0
(Program Association Table, 定义了TS中的所有节目, 是PSI信息表的根节点). 代表当前PSI表为PAT表, 我们要进行parseProgramAssociationTable
的工作.1821 - 1849: 如果
PID != 0
, 我们通过for
循环去处理每个解析出来的program
.去调用每个program -> parsePSISection
. 如果没有处理到(handle = false
), 就去处理掉这些PSISection
;
1852 - 1867: 在解析完成后, 我们对于每个Program进行parsePID
的工作;
3.6 void ATSParser::parseProgramAssociationTable(ABitReader *br)
我们在这个方法中, 处理PID == 0x0000的PAT.它的格式如下图:
上图中,程序在解析到N环部分的时候,会读取并保存节目列表及其PID。PAT信息在TS流中隔一段时间就会传送,接收机在接收时,以接收PAT表为起始。PAT表列出了TS流中所有的节目列表,以及节目对应的PID值,这个PID值表征的是该节目对应的PMT表的PID值(PMT表稍后说明)。PAT表与PMT的关系如下图。(这一段引用自 TS流基本概念)
了解到这一步就可以着手于代码了, 小弟这就上代码.
1712 void ATSParser::parseProgramAssociationTable(ABitReader *br) { //简称parsePAT
1713 unsigned table_id = br->getBits(8);
1714 ALOGV(" table_id = %u", table_id);
1715 if (table_id != 0x00u) {
1716 ALOGE("PAT data error!");
1717 return ;
1718 }
1719 unsigned section_syntax_indictor = br->getBits(1);
1720 ALOGV(" section_syntax_indictor = %u", section_syntax_indictor);
1721
1722 br->skipBits(1); // '0'
1723 MY_LOGV(" reserved = %u", br->getBits(2));
1724
1725 unsigned section_length = br->getBits(12);
1726 ALOGV(" section_length = %u", section_length);
1727
1728 MY_LOGV(" transport_stream_id = %u", br->getBits(16));
1729 MY_LOGV(" reserved = %u", br->getBits(2));
1730 MY_LOGV(" version_number = %u", br->getBits(5));
1731 MY_LOGV(" current_next_indicator = %u", br->getBits(1));
1732 MY_LOGV(" section_number = %u", br->getBits(8));
1733 MY_LOGV(" last_section_number = %u", br->getBits(8));
1734
1735 size_t numProgramBytes = (section_length - 5 /* header */ - 4 /* crc */);
1736
1737 for (size_t i = 0; i < numProgramBytes / 4; ++i) {
1738 unsigned program_number = br->getBits(16);
1739 ALOGV(" program_number = %u", program_number);
1740
1741 MY_LOGV(" reserved = %u", br->getBits(3));
1742
1743 if (program_number == 0) {
1744 MY_LOGV(" network_PID = 0x%04x", br->getBits(13));
1745 } else {
1746 unsigned programMapPID = br->getBits(13);
1747
1748 ALOGV(" program_map_PID = 0x%04x", programMapPID);
1749
1750 bool found = false;
1751 for (size_t index = 0; index < mPrograms.size(); ++index) {
1752 const sp &program = mPrograms.itemAt(index);
1753
1754 if (program->number() == program_number) {
1755 program->updateProgramMapPID(programMapPID);
1756 found = true;
1757 break;
1758 }
1759 }
1760
1761 if (!found) {
1762 mPrograms.push(
1763 new Program(this, program_number, programMapPID, mLastRecoveredPTS));
1764 if (mSampleAesKeyItem != NULL) {
1765 mPrograms.top()->signalNewSampleAesKey(mSampleAesKeyItem);
1766 }
1767 }
1768
1769 if (mPSISections.indexOfKey(programMapPID) < 0) {
1770 mPSISections.add(programMapPID, new PSISection);
1771 }
1772 }
1773 }
1774
1775 MY_LOGV(" CRC = 0x%08x", br->getBits(32));
1776 }
1713 - 1718: 读取8bit, 获取table_id. 判断一下table_id == 0x00
;
1719 - 1720: 读取1bit, 分段句法指示符;
1722 - 1723: skip '0';
1725 - 1726: 读取12bit, 分段长度;
1735: 计算numProgramBytes
= section_length
- header的长度(5)
- CRC校验所占长度(4)
;
1737 - 1773: 开始for
循环, 从循环条件可以看到, 每次处理4个Byte.
- 1738 -1739: 读取16bit -> 节目号(program_number);
- 1743 - 1744:
(program_number == 0)
代表着这个PSI表为NAT表. 紧接着就去读取13bit -> 网络PID(network_PID
); - 1746 - 1748: 如果不是
program_number != 0
, 读取13bit -> 节目映射号(program_map_PID
); - 1751 - 1759: 根据节目号
program_number
去节目Vector
寻找. 如果找到了, 那么就更新节目号对应的节目ID; - 1761 - 1767: 如果没有找到, 那就将当前的
program
加入到Vector
中去; - 1769 - 1771: 最后, 如果
KeyedVector
中没有加入当前的> mPSISections program_map_PID
, 那么就加入其中
1775: 读取32bit, 给出最后的CRC校验位;
小结一下: 从代码中可以知道:
①: mPSISections
中组织着key
为PID
, value
为sp
的keyVector;
②: mPrograms
中组织着sp
的Vector;
在此方法中维护的这两点, 会在我们在3.5 status_t ATSParser::parsePID
中使用得到. 至此, 我们将进入ATSParse
的内部类ATSParser::Program
去分析在3.5中调用的两个方法: ① parsePSISection
; ② parsePID
.
4 开启"节目"的大门
经过长途的跋涉, 我们来到了"Program"游乐园的门口. 闲话少说, 我们构造一张"门票", 看看"门票"代码.
4.1 ATSParser::Program::Program( ATSParser *parser, unsigned programNumber, unsigned programMapPID, int64_t lastRecoveredPTS))
285 ATSParser::Program::Program(
286 ATSParser *parser, unsigned programNumber, unsigned programMapPID,
287 int64_t lastRecoveredPTS)
288 : mParser(parser),
289 mProgramNumber(programNumber),
290 mProgramMapPID(programMapPID),
291 mFirstPTSValid(false),
292 mFirstPTS(0),
293 mLastRecoveredPTS(lastRecoveredPTS) {
294 ALOGV("new program number %u", programNumber);
295 }
288 - 294: 拿到节目号, 节目ID, PTS标志位和PTS, 还有最后恢复PTS. 最后announce出来, 新的program号.
Ps: 哈哈, 门票还是很好拿的说~
4.1
297 bool ATSParser::Program::parsePSISection(
298 unsigned pid, ABitReader *br, status_t *err) {
299 *err = OK;
300
301 if (pid != mProgramMapPID) {
302 return false;
303 }
304
305 *err = parseProgramMap(br);
306
307 return true;
308}
301 - 302: 再次检查传入的pid
是否和当前实例的mProgramMapPID
相等;
305: 走parseProgramMap
;
4.1.1 status_t ATSParser::Program::parseProgramMap(ABitReader *br)
"每个简单的方法背后,都有另一个复杂的方法 ^_^ "诚然, 既然parsePSISection
这么简单, 那么parseProgramMap
一定很复杂咯. 但在此之前, 我们回顾下PMT表的结构, 如下图所示:
程序在读取N环的时候会读取该节目所有的码流列表及其PID,解析的时候可以根据PID来分离。这N环描述符包括的信息如下图所示。
节目时钟参考PCR的PID和视频的PID是相等的。由PAT得出所有的节目列表,选定收看的节目后,筛选出等于该节目PID的TS包,就可以得到该节目的所有码流的PID映射表,这样接收机就可以只接收PID等于该节目的码流的TS包即可收看该节目。(这一段引用自TS流基本概念)
现在我们看看其冗长的代码吧.
456 status_t ATSParser::Program::parseProgramMap(ABitReader *br) {
457 unsigned table_id = br->getBits(8);
458 ALOGV(" table_id = %u", table_id);
459 if (table_id != 0x02u) {
460 ALOGE("PMT data error!");
461 return ERROR_MALFORMED;
462 }
463 unsigned section_syntax_indicator = br->getBits(1);
464 ALOGV(" section_syntax_indicator = %u", section_syntax_indicator);
465 if (section_syntax_indicator != 1u) {
466 ALOGE("PMT data error!");
467 return ERROR_MALFORMED;
468 }
469
470 br->skipBits(1); // '0'
471 MY_LOGV(" reserved = %u", br->getBits(2));
472
473 unsigned section_length = br->getBits(12);
474 ALOGV(" section_length = %u", section_length);
475
476 MY_LOGV(" program_number = %u", br->getBits(16));
477 MY_LOGV(" reserved = %u", br->getBits(2));
478 MY_LOGV(" version_number = %u", br->getBits(5));
479 MY_LOGV(" current_next_indicator = %u", br->getBits(1));
480 MY_LOGV(" section_number = %u", br->getBits(8));
481 MY_LOGV(" last_section_number = %u", br->getBits(8));
482 MY_LOGV(" reserved = %u", br->getBits(3));
483
484 unsigned PCR_PID = br->getBits(13);
485 ALOGV(" PCR_PID = 0x%04x", PCR_PID);
486
487 MY_LOGV(" reserved = %u", br->getBits(4));
488
489 unsigned program_info_length = br->getBits(12);
490 ALOGV(" program_info_length = %u", program_info_length);
491
492 // descriptors
493 CADescriptor programCA;
494 bool hasProgramCA = findCADescriptor(br, program_info_length, &programCA);
495 if (hasProgramCA && !mParser->mCasManager->addProgram(
496 mProgramNumber, programCA)) {
497 return ERROR_MALFORMED;
498 }
499
500 Vector infos;
501
502 // infoBytesRemaining is the number of bytes that make up the
503 // variable length section of ES_infos. It does not include the
504 // final CRC.
505 size_t infoBytesRemaining = section_length - 9 - program_info_length - 4;
506
507 while (infoBytesRemaining >= 5) {
508
509 unsigned streamType = br->getBits(8);
510 ALOGV(" stream_type = 0x%02x", streamType);
511
512 MY_LOGV(" reserved = %u", br->getBits(3));
513
514 unsigned elementaryPID = br->getBits(13);
515 ALOGV(" elementary_PID = 0x%04x", elementaryPID);
516
517 MY_LOGV(" reserved = %u", br->getBits(4));
518
519 unsigned ES_info_length = br->getBits(12);
520 ALOGV(" ES_info_length = %u", ES_info_length);
521
522 CADescriptor streamCA;
523 bool hasStreamCA = findCADescriptor(br, ES_info_length, &streamCA);
524 if (hasStreamCA && !mParser->mCasManager->addStream(
525 mProgramNumber, elementaryPID, streamCA)) {
526 return ERROR_MALFORMED;
527 }
528 StreamInfo info;
529 info.mType = streamType;
530 info.mPID = elementaryPID;
531 info.mCASystemId = hasProgramCA ? programCA.mSystemID :
532 hasStreamCA ? streamCA.mSystemID : -1;
533 infos.push(info);
534
535 infoBytesRemaining -= 5 + ES_info_length;
536 }
537
538 if (infoBytesRemaining != 0) {
539 ALOGW("Section data remains unconsumed");
540 }
541 MY_LOGV(" CRC = 0x%08x", br->getBits(32));
542
543 bool PIDsChanged = false;
544 for (size_t i = 0; i < infos.size(); ++i) {
545 StreamInfo &info = infos.editItemAt(i);
546
547 ssize_t index = mStreams.indexOfKey(info.mPID);
548
549 if (index >= 0 && mStreams.editValueAt(index)->type() != info.mType) {
550 ALOGI("uh oh. stream PIDs have changed.");
551 PIDsChanged = true;
552 break;
553 }
554 }
555
556 if (PIDsChanged) {
557#if 0
558 ALOGI("before:");
559 for (size_t i = 0; i < mStreams.size(); ++i) {
560 sp stream = mStreams.editValueAt(i);
561
562 ALOGI("PID 0x%08x => type 0x%02x", stream->pid(), stream->type());
563 }
564
565 ALOGI("after:");
566 for (size_t i = 0; i < infos.size(); ++i) {
567 StreamInfo &info = infos.editItemAt(i);
568
569 ALOGI("PID 0x%08x => type 0x%02x", info.mPID, info.mType);
570 }
571#endif
572
573 // we can recover if number of streams for each type remain the same
574 bool success = switchPIDs(infos);
575
576 if (!success) {
577 ALOGI("Stream PIDs changed and we cannot recover.");
578 return ERROR_MALFORMED;
579 }
580 }
581
582 bool isAddingScrambledStream = false;
583 for (size_t i = 0; i < infos.size(); ++i) {
584 StreamInfo &info = infos.editItemAt(i);
585
586 if (mParser->mCasManager->isCAPid(info.mPID)) {
587 // skip CA streams (EMM/ECM)
588 continue;
589 }
590 ssize_t index = mStreams.indexOfKey(info.mPID);
591
592 if (index < 0) {
593 sp stream = new Stream(
594 this, info.mPID, info.mType, PCR_PID, info.mCASystemId);
595
596 if (mSampleAesKeyItem != NULL) {
597 stream->signalNewSampleAesKey(mSampleAesKeyItem);
598 }
599
600 isAddingScrambledStream |= info.mCASystemId >= 0;
601 mStreams.add(info.mPID, stream);
602 }
603 }
604
605 if (isAddingScrambledStream) {
606 ALOGI("Receiving scrambled streams without descrambler!");
607 return ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED;
608 }
609 return OK;
610 }
457 - 462: 读取8it -> table_id
. 如果table_id != 0x02
, 返回畸形的;
473: 读取12bit -> section_length
;
489 - 490: 读取12bit -> program_info_length
(节目信息长度);
500: 定义一个Vector
来装当前Program
中所带的Stream
信息
502 - 505: 根据注释, 我们知道infoBytesRemaining
是用来组成ES_Infos
"可变长度分段"的Byte数;
507 - 536: 当infoBytesRemaining > 5
条件满足的时候, 就进入循环搞事情;
- 509 - 510: 读取8bit ->
streamType
(流类型); - 514 - 515: 读取13bit ->
elementaryPID
(基本PID); - 519 - 520: 读取12bit ->
ES_info_length
(ES信息长度);
543 - 554: 使用一个for循环, 去检测stream的stream-> type()
是否有变化, 如果有变化, PIDsChanged
置位为true
, 接下来还要做些处理. 这里要注意下两个变量的类型. ①infos
: Vector
; ②mStreams
: KeyedVector
;
556 - 580: 如果上一步检测同一个PID的Stream的tpye是有变化的.
- 574: 根据注释以及
switchPIDs
的源码, 我的得知: 如果当每个type的stream数量相同的时候, 就去更换. - 576 - 579: 没有成功, 返回畸形的;
582 - 603: 在刚刚组织出来的infos
中寻找, 将没有加入到mStream
中的info
信息加入其中.
小结一下: 至此, 我们已经将所有的节目(Program), 以及每个节目中的A/V流(Stream)识别出来了. 分别放在了mPrograms
和mStream`中, 以便后面使用.
4.2 bool ATSParser::Program::parsePID
310 bool ATSParser::Program::parsePID(
311 unsigned pid, unsigned continuity_counter,
312 unsigned payload_unit_start_indicator,
313 unsigned transport_scrambling_control,
314 unsigned random_access_indicator,
315 ABitReader *br, status_t *err, SyncEvent *event) {
316 *err = OK;
317
318 ssize_t index = mStreams.indexOfKey(pid);
319 if (index < 0) {
320 return false;
321 }
322
323 *err = mStreams.editValueAt(index)->parse(
324 continuity_counter,
325 payload_unit_start_indicator,
326 transport_scrambling_control,
327 random_access_indicator,
328 br, event);
329
330 return true;
331 }
不知各位看官是否还记得, 在ATSParse::parsePID
之中, 我们在完成parsePSISection
之后, 我们就要开始执行ATSParser::Program::parsePID
了.现在来简单解析一下.
318 - 321: 由传入的pid
, 找到本program
对应的stream
. 并做一下简单的判断, 如果没有找到, 直接返回false.
323 - 328: 接着就直接走到了ATSParser
的另外一个内部类ATSParser::Stream
, 使用它的成员函数parse
去解析每个流的数据.
5. ATSParser::Stream
在我们找到了PAT -> PMT -> Stream后, 我们在这里就开始解析每个Stream
的相关信息. 按照惯例, 我们首先要来看看其构造函数的样子, 代码如下:
5.1 ATSParser::Stream::Stream
706 static const size_t kInitialStreamBufferSize = 192 * 1024;
707
708 ATSParser::Stream::Stream(
709 Program *program,
710 unsigned elementaryPID,
711 unsigned streamType,
712 unsigned PCR_PID,
713 int32_t CA_system_ID)
714 : mProgram(program),
715 mElementaryPID(elementaryPID),
716 mStreamType(streamType),
717 mPCR_PID(PCR_PID),
718 mExpectedContinuityCounter(-1),
719 mPayloadStarted(false),
720 mEOSReached(false),
721 mPrevPTS(0),
722 mQueue(NULL),
723 mScrambled(CA_system_ID >= 0) {
724
725 mSampleEncrypted =
726 mStreamType == STREAMTYPE_H264_ENCRYPTED ||
727 mStreamType == STREAMTYPE_AAC_ENCRYPTED ||
728 mStreamType == STREAMTYPE_AC3_ENCRYPTED;
729
730 ALOGV("new stream PID 0x%02x, type 0x%02x, scrambled %d, SampleEncrypted: %d",
731 elementaryPID, streamType, mScrambled, mSampleEncrypted);
732
733 uint32_t flags =
734 (isVideo() && mScrambled) ? ElementaryStreamQueue::kFlag_ScrambledData :
735 (mSampleEncrypted) ? ElementaryStreamQueue::kFlag_SampleEncryptedData :
736 0;
737
738 ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID;
739
740 switch (mStreamType) {
741 case STREAMTYPE_H264:
742 case STREAMTYPE_H264_ENCRYPTED:
743 mode = ElementaryStreamQueue::H264;
744 flags |= (mProgram->parserFlags() & ALIGNED_VIDEO_DATA) ?
745 ElementaryStreamQueue::kFlag_AlignedData : 0;
746 break;
747
748 case STREAMTYPE_MPEG2_AUDIO_ADTS:
749 case STREAMTYPE_AAC_ENCRYPTED:
750 mode = ElementaryStreamQueue::AAC;
751 break;
752
753 case STREAMTYPE_MPEG1_AUDIO:
754 case STREAMTYPE_MPEG2_AUDIO:
755 mode = ElementaryStreamQueue::MPEG_AUDIO;
756 break;
757
758 case STREAMTYPE_MPEG1_VIDEO:
759 case STREAMTYPE_MPEG2_VIDEO:
760 mode = ElementaryStreamQueue::MPEG_VIDEO;
761 break;
762
763 case STREAMTYPE_MPEG4_VIDEO:
764 mode = ElementaryStreamQueue::MPEG4_VIDEO;
765 break;
766
767 case STREAMTYPE_LPCM_AC3:
768 case STREAMTYPE_AC3:
769 case STREAMTYPE_AC3_ENCRYPTED:
770 mode = ElementaryStreamQueue::AC3;
771 break;
772
773 case STREAMTYPE_METADATA:
774 mode = ElementaryStreamQueue::METADATA;
775 break;
776
777 default:
778 ALOGE("stream PID 0x%02x has invalid stream type 0x%02x",
779 elementaryPID, streamType);
780 return;
781 }
782
783 mQueue = new ElementaryStreamQueue(mode, flags);
784
785 if (mQueue != NULL) {
786 if (mSampleAesKeyItem != NULL) {
787 mQueue->signalNewSampleAesKey(mSampleAesKeyItem);
788 }
789
790 ensureBufferCapacity(kInitialStreamBufferSize);
791
792 if (mScrambled && (isAudio() || isVideo())) {
793 // Set initial format to scrambled
794 sp meta = new MetaData();
795 meta->setCString(kKeyMIMEType,
796 isAudio() ? MEDIA_MIMETYPE_AUDIO_SCRAMBLED
797 : MEDIA_MIMETYPE_VIDEO_SCRAMBLED);
798 // for MediaExtractor.CasInfo
799 meta->setInt32(kKeyCASystemID, CA_system_ID);
800 mSource = new AnotherPacketSource(meta);
801 }
802 }
803 }
这个构造函数看起来很冗长, 但是实质上没做啥事, 让小弟给各位看官稍加解释.
740 - 781: 根据之前在parseProgramMap
中得到streamType
, 我们要new一个ElementaryStreamQueue
出来. 那ElementaryStreamQueue
又是干神马的咧? 这里只能告诉大家是将最终解析出来的数据组织成一个ABuffer
, 这个ABuffer
是下一层用作解码的单元Buffer(应该是很重要的单元吧).
792 - 801: 如果加了干扰, 并且有A/V, 那么我们就new一个MetaData
, 并且把关键字为kKeyMIMEType
的媒体类型设置其中. 然后再根据这个meta
, 去创建一个AnotherPacketSource
出来, 并放入mSource
中.
5.2 status_t ATSParser::Stream::parse
855 status_t ATSParser::Stream::parse(
856 unsigned continuity_counter,
857 unsigned payload_unit_start_indicator,
858 unsigned transport_scrambling_control,
859 unsigned random_access_indicator,
860 ABitReader *br, SyncEvent *event) {
861 if (mQueue == NULL) {
862 return OK;
863 }
864
865 if (mExpectedContinuityCounter >= 0
866 && (unsigned)mExpectedContinuityCounter != continuity_counter) {
867 ALOGI("discontinuity on stream pid 0x%04x", mElementaryPID);
868
869 mPayloadStarted = false;
870 mPesStartOffsets.clear();
871 mBuffer->setRange(0, 0);
872 mSubSamples.clear();
873 mExpectedContinuityCounter = -1;
874
875#if 0
876 // Uncomment this if you'd rather see no corruption whatsoever on
877 // screen and suspend updates until we come across another IDR frame.
878
879 if (mStreamType == STREAMTYPE_H264) {
880 ALOGI("clearing video queue");
881 mQueue->clear(true /* clearFormat */);
882 }
883#endif
884
885 if (!payload_unit_start_indicator) {
886 return OK;
887 }
888 }
889
890 mExpectedContinuityCounter = (continuity_counter + 1) & 0x0f;
891
892 if (payload_unit_start_indicator) {
893 off64_t offset = (event != NULL) ? event->getOffset() : 0;
894 if (mPayloadStarted) {
895 // Otherwise we run the danger of receiving the trailing bytes
896 // of a PES packet that we never saw the start of and assuming
897 // we have a a complete PES packet.
898
899 status_t err = flush(event);
900
901 if (err != OK) {
902 ALOGW("Error (%08x) happened while flushing; we simply discard "
903 "the PES packet and continue.", err);
904 }
905 }
906
907 mPayloadStarted = true;
908 // There should be at most 2 elements in |mPesStartOffsets|.
909 while (mPesStartOffsets.size() >= 2) {
910 mPesStartOffsets.erase(mPesStartOffsets.begin());
911 }
912 mPesStartOffsets.push_back(offset);
913 }
914
915 if (!mPayloadStarted) {
916 return OK;
917 }
918
919 size_t payloadSizeBits = br->numBitsLeft();
920 if (payloadSizeBits % 8 != 0u) {
921 ALOGE("Wrong value");
922 return BAD_VALUE;
923 }
924
925 size_t neededSize = mBuffer->size() + payloadSizeBits / 8;
926 ensureBufferCapacity(neededSize);
927
928 memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
929 mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
930
931 if (mScrambled) {
932 mSubSamples.push_back({payloadSizeBits / 8,
933 transport_scrambling_control, random_access_indicator});
934 }
935
936 return OK;
937 }
在看完构造函数以后, 我们来看一看他的parse方法.
865 - 888: 在构造函数中, mExpectedContinuityCounter = -1
.所在在刚刚开始parse的时候是不走这个if
的;
892 - 913: 如有有"有效载荷单元起始指示符", 则说明当前Parse的TS包内有PES包的第一个字节. (前面有提到过, 如果TS包带有的是PSI数据时, 那么有"有效载荷单元指示符", 代表着这个TS包包含PSI部分的第一个字节);
- 894 - 905: 重点: 如果当前payload开始处理了(
mPayloadStarted = true
), 执行flush
.(在第一次进入parse
方法的时候, 是不进入这个分支的); - 907: 标识当前payload开始工作了(
mPayloadStarted = true
); - 909 - 912: 如果
mPesStartOffsets
维护的List
队列中高于两个元素的时候, 将队列头erase
(也就是说, 这个列表中, 只维护0 - 1个offset
在其中). 然后将最新的offset
加入List
中;
915 - 917: 如果当前payload还没开始(!mPayloadStarted
), return OK
;
919 - 923: 获取payloadSizeBits
, 并检测其是否是整数Byte;
925 - 926: 计算出我们需要的Buffer的Size, 并调用ensureBufferCapacity
, 去判断是否有空间去申请更大的Buffer.
928 - 929: 将br所指向的Data(这个时候, 它指向的是ES数据), 全部copy到mBuffer
(ABuffer
)后. 然后设置一下mBuffer
的有效范围;
931 - 934: 如果有加扰设置, 使用mSubSamples
维护下List
;
5.4 status_t ATSParser::Stream::flush(SyncEvent *event)
1452 status_t ATSParser::Stream::flush(SyncEvent *event) {
1453 if (mBuffer == NULL || mBuffer->size() == 0) {
1454 return OK;
1455 }
1456
1457 ALOGV("flushing stream 0x%04x size = %zu", mElementaryPID, mBuffer->size());
1458
1459 status_t err = OK;
1460 if (mScrambled) {
1461 err = flushScrambled(event);
1462 mSubSamples.clear();
1463 } else {
1464 ABitReader br(mBuffer->data(), mBuffer->size());
1465 err = parsePES(&br, event);
1466 }
1467
1468 mBuffer->setRange(0, 0);
1469
1470 return err;
1471 }
在parse
方法中, 我们在mPayloadStart == true
的时候, 会调用这个方法去"冲刷"buffer.
1453 - 1455: 判断mBuffer
是否可操作;
1460 - 1462: 如果在前面的parse工作中, 发现这个TS包是有mScrambled
标识的, 那么走flushScrambled
(在这里先不讨论这个方法);
1463 - 1466: 重点: 初始化一个ABitReader
去读取组织好的一个ABuffer
. 然后走parsePES
;
1468: 将当前handle的ABuffer的有效区域设置为(0, 0)(也就是说不可操作了);
5.5 ATSParser::Stream::parsePES
哈哈, 我们终于走到parsePES
了. 终于可以看到究竟是如何处理ES数据包了!别急, 在看冗长的代码前, 我们先回顾来PES的结构表.
标识名 | bit | 描述 |
---|---|---|
pes start code | 24 | 开始码,固定为0x000001 |
stream id | 8 | 音频取值(0xc0-0xdf ),通常为0xc0 <-> 视频取值(0xe0-0xef ),通常为0xe0 |
pes packet length | 16 | 后面pes数据的长度, 0 表示长度不限制, 只有视频数据长度会超过0xffff |
flag | 8 | 通常取值0x80 ,表示数据不加密、无优先级、备份的数据 |
flag | 8 | 取值0x80 表示只含有pts,取值0xc0 表示含有pts和dts |
pes data length | 8 | 后面数据的长度,取值5 或10 |
pts | 33 | presentation time stamp |
dts | 33 | decode time stamp |
复习完这个表, 我们就可以进入代码的海洋了(这个parsePES
方法真的好长o(╥﹏╥)o).
1037 status_t ATSParser::Stream::parsePES(ABitReader *br, SyncEvent *event) {
1038 const uint8_t *basePtr = br->data();
1039
1040 unsigned packet_startcode_prefix = br->getBits(24);
1041
1042 ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
1043
1044 if (packet_startcode_prefix != 1) {
1045 ALOGV("Supposedly payload_unit_start=1 unit does not start "
1046 "with startcode.");
1047
1048 return ERROR_MALFORMED;
1049 }
1050
1051 unsigned stream_id = br->getBits(8);
1052 ALOGV("stream_id = 0x%02x", stream_id);
1053
1054 unsigned PES_packet_length = br->getBits(16);
1055 ALOGV("PES_packet_length = %u", PES_packet_length);
1056
1057 if (stream_id != 0xbc // program_stream_map
1058 && stream_id != 0xbe // padding_stream
1059 && stream_id != 0xbf // private_stream_2
1060 && stream_id != 0xf0 // ECM
1061 && stream_id != 0xf1 // EMM
1062 && stream_id != 0xff // program_stream_directory
1063 && stream_id != 0xf2 // DSMCC
1064 && stream_id != 0xf8) { // H.222.1 type E
1065 if (br->getBits(2) != 2u) {
1066 return ERROR_MALFORMED;
1067 }
1068
1069 unsigned PES_scrambling_control = br->getBits(2);
1070 ALOGV("PES_scrambling_control = %u", PES_scrambling_control);
1071
1072 MY_LOGV("PES_priority = %u", br->getBits(1));
1073 MY_LOGV("data_alignment_indicator = %u", br->getBits(1));
1074 MY_LOGV("copyright = %u", br->getBits(1));
1075 MY_LOGV("original_or_copy = %u", br->getBits(1));
1076
1077 unsigned PTS_DTS_flags = br->getBits(2);
1078 ALOGV("PTS_DTS_flags = %u", PTS_DTS_flags);
1079
1080 unsigned ESCR_flag = br->getBits(1);
1081 ALOGV("ESCR_flag = %u", ESCR_flag);
1082
1083 unsigned ES_rate_flag = br->getBits(1);
1084 ALOGV("ES_rate_flag = %u", ES_rate_flag);
1085
1086 unsigned DSM_trick_mode_flag = br->getBits(1);
1087 ALOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag);
1088
1089 unsigned additional_copy_info_flag = br->getBits(1);
1090 ALOGV("additional_copy_info_flag = %u", additional_copy_info_flag);
1091
1092 MY_LOGV("PES_CRC_flag = %u", br->getBits(1));
1093 MY_LOGV("PES_extension_flag = %u", br->getBits(1));
1094
1095 unsigned PES_header_data_length = br->getBits(8);
1096 ALOGV("PES_header_data_length = %u", PES_header_data_length);
1097
1098 unsigned optional_bytes_remaining = PES_header_data_length;
1099
1100 uint64_t PTS = 0, DTS = 0;
1101
1102 if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
1103 if (optional_bytes_remaining < 5u) {
1104 return ERROR_MALFORMED;
1105 }
1106
1107 if (br->getBits(4) != PTS_DTS_flags) {
1108 return ERROR_MALFORMED;
1109 }
1110 PTS = ((uint64_t)br->getBits(3)) << 30;
1111 if (br->getBits(1) != 1u) {
1112 return ERROR_MALFORMED;
1113 }
1114 PTS |= ((uint64_t)br->getBits(15)) << 15;
1115 if (br->getBits(1) != 1u) {
1116 return ERROR_MALFORMED;
1117 }
1118 PTS |= br->getBits(15);
1119 if (br->getBits(1) != 1u) {
1120 return ERROR_MALFORMED;
1121 }
1122
1123 ALOGV("PTS = 0x%016" PRIx64 " (%.2f)", PTS, PTS / 90000.0);
1124
1125 optional_bytes_remaining -= 5;
1126
1127 if (PTS_DTS_flags == 3) {
1128 if (optional_bytes_remaining < 5u) {
1129 return ERROR_MALFORMED;
1130 }
1131
1132 if (br->getBits(4) != 1u) {
1133 return ERROR_MALFORMED;
1134 }
1135
1136 DTS = ((uint64_t)br->getBits(3)) << 30;
1137 if (br->getBits(1) != 1u) {
1138 return ERROR_MALFORMED;
1139 }
1140 DTS |= ((uint64_t)br->getBits(15)) << 15;
1141 if (br->getBits(1) != 1u) {
1142 return ERROR_MALFORMED;
1143 }
1144 DTS |= br->getBits(15);
1145 if (br->getBits(1) != 1u) {
1146 return ERROR_MALFORMED;
1147 }
1148
1149 ALOGV("DTS = %" PRIu64, DTS);
1150
1151 optional_bytes_remaining -= 5;
1152 }
1153 }
1154
1155 if (ESCR_flag) {
1156 if (optional_bytes_remaining < 6u) {
1157 return ERROR_MALFORMED;
1158 }
1159
1160 br->getBits(2);
1161
1162 uint64_t ESCR = ((uint64_t)br->getBits(3)) << 30;
1163 if (br->getBits(1) != 1u) {
1164 return ERROR_MALFORMED;
1165 }
1166 ESCR |= ((uint64_t)br->getBits(15)) << 15;
1167 if (br->getBits(1) != 1u) {
1168 return ERROR_MALFORMED;
1169 }
1170 ESCR |= br->getBits(15);
1171 if (br->getBits(1) != 1u) {
1172 return ERROR_MALFORMED;
1173 }
1174
1175 ALOGV("ESCR = %" PRIu64, ESCR);
1176 MY_LOGV("ESCR_extension = %u", br->getBits(9));
1177
1178 if (br->getBits(1) != 1u) {
1179 return ERROR_MALFORMED;
1180 }
1181
1182 optional_bytes_remaining -= 6;
1183 }
1184
1185 if (ES_rate_flag) {
1186 if (optional_bytes_remaining < 3u) {
1187 return ERROR_MALFORMED;
1188 }
1189
1190 if (br->getBits(1) != 1u) {
1191 return ERROR_MALFORMED;
1192 }
1193 MY_LOGV("ES_rate = %u", br->getBits(22));
1194 if (br->getBits(1) != 1u) {
1195 return ERROR_MALFORMED;
1196 }
1197
1198 optional_bytes_remaining -= 3;
1199 }
1200
1201 br->skipBits(optional_bytes_remaining * 8);
1202
1203 // ES data follows.
1204 int32_t pesOffset = br->data() - basePtr;
1205
1206 if (PES_packet_length != 0) {
1207 if (PES_packet_length < PES_header_data_length + 3) {
1208 return ERROR_MALFORMED;
1209 }
1210
1211 unsigned dataLength =
1212 PES_packet_length - 3 - PES_header_data_length;
1213
1214 if (br->numBitsLeft() < dataLength * 8) {
1215 ALOGE("PES packet does not carry enough data to contain "
1216 "payload. (numBitsLeft = %zu, required = %u)",
1217 br->numBitsLeft(), dataLength * 8);
1218
1219 return ERROR_MALFORMED;
1220 }
1221
1222 ALOGV("There's %u bytes of payload, PES_packet_length=%u, offset=%d",
1223 dataLength, PES_packet_length, pesOffset);
1224
1225 onPayloadData(
1226 PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
1227 br->data(), dataLength, pesOffset, event);
1228
1229 br->skipBits(dataLength * 8);
1230 } else {
1231 onPayloadData(
1232 PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
1233 br->data(), br->numBitsLeft() / 8, pesOffset, event);
1234
1235 size_t payloadSizeBits = br->numBitsLeft();
1236 if (payloadSizeBits % 8 != 0u) {
1237 return ERROR_MALFORMED;
1238 }
1239
1240 ALOGV("There's %zu bytes of payload, offset=%d",
1241 payloadSizeBits / 8, pesOffset);
1242 }
1243 } else if (stream_id == 0xbe) { // padding_stream
1244 if (PES_packet_length == 0u) {
1245 return ERROR_MALFORMED;
1246 }
1247 br->skipBits(PES_packet_length * 8);
1248 } else {
1249 if (PES_packet_length == 0u) {
1250 return ERROR_MALFORMED;
1251 }
1252 br->skipBits(PES_packet_length * 8);
1253 }
1254
1255 return OK;
1256 }
1040 - 1049 : 读取24bit -> packet_startcode_prefix
(pes开始的前缀码). 如果前缀码不为1
, 直接返回畸形的;
1051 - 1052: 读取8bit -> stream_id
;
1054 - 1055: 读取16bit -> PES包长度(PES_packet_length
);
1057 - 1242: 如果stream_id
不为代码中列出的类型, 进行如下操作:
1065 - 1067: 读取2bit, 如果不为2, 则返回畸形;
1069 - 1096: 陆续parse出一些信息; 其中比较有用的是
PES_header_data_length
并存入optional_bytes_remaining
变量;1100 - 1153: 计算PTS和DTS,
optional_bytes_remaining -= 5
(这说明, PTS/DTS段各占用了5Byte);1155 - 1183: 如
ESCR_flag == true
, 就进行对ESCR的操作,optional_bytes_remaining -= 6
(这说明, ESCR_flag 段占用了6Byte);1185 - 1199: 如
ES_rate_flag == true
, 进行对应的操作,optional_bytes_remaining -= 3
(这说明, ES_rate_flag 段占用了3Byte);1201: 跳过剩余的
optional_bytes_remaining
;1203 - 1204: 重点: 我们即将开始看到ES Data的操作了. 计算当前从PES开始到目前为止的Offset, 放入
pesOffset
中;-
1206 - 1229: 如果
PES_packet_length
不为0
.- 1207 - 1209: 如果
PES_packet_length < PES_header_data_length + 3
, 返回"畸形"; - 1211 - 1212: 计算
dataLength
; - 1214 - 1220: 如果剩下的bit数 < dataLength * 8, 返回"畸形的";
- 1225 - 1228: 重点: 走进onPayloadData, 去将我们得到的payload信息放入
ESQueue
管理的ABuffer
中;
- 1207 - 1209: 如果
-
如果
PES_packet_length
是其他情况.;- 1231 - 1233: 直接调用
onPayloadData
; - 1235 - 1238: 计算
payloadSizeBits
, 如果不是整数Byte, 返回"畸形的";
- 1231 - 1233: 直接调用
1243 - 1247: 如果stream_id == 0xbe
(填充的stream). 那么如果PES长度为0 , 直接返回畸形. 否则, 就skip掉这个PES包;
1248 - 1253: 最后stream_id
均不属于上述几种的话, 如果PES长度为0 , 直接返回畸形. 否则, 就skip掉这个PES包;
5.6 ATSParser::Stream::onPayloadData
1473 void ATSParser::Stream::onPayloadData(
1474 unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */,
1475 unsigned PES_scrambling_control,
1476 const uint8_t *data, size_t size,
1477 int32_t payloadOffset, SyncEvent *event) {
1478#if 0
1479 ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld",
1480 mStreamType,
1481 PTS,
1482 (int64_t)PTS - mPrevPTS);
1483 mPrevPTS = PTS;
1484#endif
1485
1486 ALOGV("onPayloadData mStreamType=0x%02x size: %zu", mStreamType, size);
1487
1488 int64_t timeUs = 0ll; // no presentation timestamp available.
1489 if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
1490 timeUs = mProgram->convertPTSToTimestamp(PTS);
1491 }
1492
1493 status_t err = mQueue->appendData(
1494 data, size, timeUs, payloadOffset, PES_scrambling_control);
1495
1496 if (mEOSReached) {
1497 mQueue->signalEOS();
1498 }
1499
1500 if (err != OK) {
1501 return;
1502 }
1503
1504 sp accessUnit;
1505 bool found = false;
1506 while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) {
1507 if (mSource == NULL) {
1508 sp meta = mQueue->getFormat();
1509
1510 if (meta != NULL) {
1511 ALOGV("Stream PID 0x%08x of type 0x%02x now has data.",
1512 mElementaryPID, mStreamType);
1513
1514 const char *mime;
1515 if (meta->findCString(kKeyMIMEType, &mime)
1516 && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
1517 int32_t sync = 0;
1518 if (!accessUnit->meta()->findInt32("isSync", &sync) || !sync) {
1519 continue;
1520 }
1521 }
1522 mSource = new AnotherPacketSource(meta);
1523 mSource->queueAccessUnit(accessUnit);
1524 ALOGV("onPayloadData: created AnotherPacketSource PID 0x%08x of type 0x%02x",
1525 mElementaryPID, mStreamType);
1526 }
1527 } else if (mQueue->getFormat() != NULL) {
1528 // After a discontinuity we invalidate the queue's format
1529 // and won't enqueue any access units to the source until
1530 // the queue has reestablished the new format.
1531
1532 if (mSource->getFormat() == NULL) {
1533 mSource->setFormat(mQueue->getFormat());
1534 }
1535 mSource->queueAccessUnit(accessUnit);
1536 }
1537
1538 // Every access unit has a pesStartOffset queued in |mPesStartOffsets|.
1539 off64_t pesStartOffset = -1;
1540 if (!mPesStartOffsets.empty()) {
1541 pesStartOffset = *mPesStartOffsets.begin();
1542 mPesStartOffsets.erase(mPesStartOffsets.begin());
1543 }
1544
1545 if (pesStartOffset >= 0 && (event != NULL) && !found && mQueue->getFormat() != NULL) {
1546 int32_t sync = 0;
1547 if (accessUnit->meta()->findInt32("isSync", &sync) && sync) {
1548 int64_t timeUs;
1549 if (accessUnit->meta()->findInt64("timeUs", &timeUs)) {
1550 found = true;
1551 event->init(pesStartOffset, mSource, timeUs, getSourceType());
1552 }
1553 }
1554 }
1555 }
1556 }
这应该是本文中要讲解的Stream
的最后一个方法了吧, 我们来分析一下.
1488 - 1491: 如果no presentation timestamp available
. 那么, 就去看PTS_DTS_flags
. 如果符合条件, 使用方法convertPTSToTimestamp
放入timeUS
中;
**1493 - 1494: 重点: ** 调用ElementaryStreamQueue
类的appendData
方法 (这个方法, 我们会在接下来讲解);
1496 - 1502: 判断下是否EOS
和err是否OK
;
1506 - 1555: 如果accessUnit
从mQueue->dequeueAccessUnit()
获取到的ABuffer
不为空, 进入循环;
- 1510 - 1526: 如果当前Stream的
AnohterPacketSource == NULL
- 1508 - 1526: 从
mQueue
获取`MetaData, 如果获取到的不为空:- 1514 - 1521: 检查
kKeyMIMEType
是否为MEDIA_MIMETYPE_VIDEO_AVC
.;- 如果是的, 并且没有找到
isSync
标识(非同步), 就继续去做dequeueAccessUnit
;
- 如果是的, 并且没有找到
- 1514 - 1521: 检查
- 1508 - 1526: 从
- 1527 - 1536: 如果此时有了
AnotherPacketSouce
, 并且能从ElementaryStreamQueue
获取到MetaData
.- 1532 - 1533: 保证是设置有
MetaData
的; - 1535: 将
accessUnit
加入到AnotherPacketSouce
维护的队列之中;
- 1532 - 1533: 保证是设置有
- 1538 - 1554: 对
mPesStartOffsets
这个List
进行维护;
6 ElementaryStreamQueue
我们一路跋山涉水, 终于来到了终点站ElementaryStreamQueue
(此后, 我将根据其所在的文件名, 简写为ESQueue
). 惯例惯例~我们来看看其构造函数吧.
6.1 ElementaryStreamQueue::ElementaryStreamQueue
41 ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
42 : mMode(mode),
43 mFlags(flags),
44 mEOSReached(false),
45 mCASystemId(0),
46 mAUIndex(0) {
47
48 ALOGV("ElementaryStreamQueue(%p) mode %x flags %x isScrambled %d isSampleEncrypted %d",
49 this, mode, flags, isScrambled(), isSampleEncrypted());
50
51 // Create the decryptor anyway since we don't know the use-case unless key is provided
52 // Won't decrypt if key info not available (e.g., scanner/extractor just parsing ts files)
53 mSampleDecryptor = isSampleEncrypted() ? new HlsSampleDecryptor : NULL;
54 }
(⊙o⊙)…貌似没什么好说的, 好吧, 暂且就先搁这儿吧, 以后有更深刻的理解了再回来补充. 回到正题, 我们赶紧去看看appendData
以及dequeueAccessUnit
6.2 status_t ElementaryStreamQueue::appendData
274 status_t ElementaryStreamQueue::appendData(
275 const void *data, size_t size, int64_t timeUs,
276 int32_t payloadOffset, uint32_t pesScramblingControl) {
277
278 if (mEOSReached) {
279 ALOGE("appending data after EOS");
280 return ERROR_MALFORMED;
281 }
282 if (mBuffer == NULL || mBuffer->size() == 0) {
283 switch (mMode) {
284 case H264:
285 case MPEG_VIDEO:
286 {
287#if 0
288 if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
289 return ERROR_MALFORMED;
290 }
291#else
292 uint8_t *ptr = (uint8_t *)data;
293
294 ssize_t startOffset = -1;
295 for (size_t i = 0; i + 2 < size; ++i) {
296 if (!memcmp("\x00\x00\x01", &ptr[i], 3)) {
297 startOffset = i;
298 break;
299 }
300 }
301
302 if (startOffset < 0) {
303 return ERROR_MALFORMED;
304 }
305
306 if (mFormat == NULL && startOffset > 0) {
307 ALOGI("found something resembling an H.264/MPEG syncword "
308 "at offset %zd",
309 startOffset);
310 }
311
312 data = &ptr[startOffset];
313 size -= startOffset;
314#endif
315 break;
316 }
317
318 case MPEG4_VIDEO:
319 {
320#if 0
321 if (size < 3 || memcmp("\x00\x00\x01", data, 3)) {
322 return ERROR_MALFORMED;
323 }
324#else
325 uint8_t *ptr = (uint8_t *)data;
326
327 ssize_t startOffset = -1;
328 for (size_t i = 0; i + 2 < size; ++i) {
329 if (!memcmp("\x00\x00\x01", &ptr[i], 3)) {
330 startOffset = i;
331 break;
332 }
333 }
334
335 if (startOffset < 0) {
336 return ERROR_MALFORMED;
337 }
338
339 if (startOffset > 0) {
340 ALOGI("found something resembling an H.264/MPEG syncword "
341 "at offset %zd",
342 startOffset);
343 }
344
345 data = &ptr[startOffset];
346 size -= startOffset;
347#endif
348 break;
349 }
350
351 case AAC:
352 {
353 uint8_t *ptr = (uint8_t *)data;
354
355#if 0
356 if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
357 return ERROR_MALFORMED;
358 }
359#else
360 ssize_t startOffset = -1;
361 size_t frameLength;
362 for (size_t i = 0; i < size; ++i) {
363 if (IsSeeminglyValidADTSHeader(
364 &ptr[i], size - i, &frameLength)) {
365 startOffset = i;
366 break;
367 }
368 }
369
370 if (startOffset < 0) {
371 return ERROR_MALFORMED;
372 }
373
374 if (startOffset > 0) {
375 ALOGI("found something resembling an AAC syncword at "
376 "offset %zd",
377 startOffset);
378 }
379
380 if (frameLength != size - startOffset) {
381 ALOGV("First ADTS AAC frame length is %zd bytes, "
382 "while the buffer size is %zd bytes.",
383 frameLength, size - startOffset);
384 }
385
386 data = &ptr[startOffset];
387 size -= startOffset;
388#endif
389 break;
390 }
391
392 case AC3:
393 {
394 uint8_t *ptr = (uint8_t *)data;
395
396 ssize_t startOffset = -1;
397 for (size_t i = 0; i < size; ++i) {
398 if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) {
399 startOffset = i;
400 break;
401 }
402 }
403
404 if (startOffset < 0) {
405 return ERROR_MALFORMED;
406 }
407
408 if (startOffset > 0) {
409 ALOGI("found something resembling an AC3 syncword at "
410 "offset %zd",
411 startOffset);
412 }
413
414 data = &ptr[startOffset];
415 size -= startOffset;
416 break;
417 }
418
419 case MPEG_AUDIO:
420 {
421 uint8_t *ptr = (uint8_t *)data;
422
423 ssize_t startOffset = -1;
424 for (size_t i = 0; i < size; ++i) {
425 if (IsSeeminglyValidMPEGAudioHeader(&ptr[i], size - i)) {
426 startOffset = i;
427 break;
428 }
429 }
430
431 if (startOffset < 0) {
432 return ERROR_MALFORMED;
433 }
434
435 if (startOffset > 0) {
436 ALOGI("found something resembling an MPEG audio "
437 "syncword at offset %zd",
438 startOffset);
439 }
440
441 data = &ptr[startOffset];
442 size -= startOffset;
443 break;
444 }
445
446 case PCM_AUDIO:
447 case METADATA:
448 {
449 break;
450 }
451
452 default:
453 ALOGE("Unknown mode: %d", mMode);
454 return ERROR_MALFORMED;
455 }
456 }
457
458 size_t neededSize = (mBuffer == NULL ? 0 : mBuffer->size()) + size;
459 if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
460 neededSize = (neededSize + 65535) & ~65535;
461
462 ALOGV("resizing buffer to size %zu", neededSize);
463
464 sp buffer = new ABuffer(neededSize);
465 if (mBuffer != NULL) {
466 memcpy(buffer->data(), mBuffer->data(), mBuffer->size());
467 buffer->setRange(0, mBuffer->size());
468 } else {
469 buffer->setRange(0, 0);
470 }
471
472 mBuffer = buffer;
473 }
474
475 memcpy(mBuffer->data() + mBuffer->size(), data, size);
476 mBuffer->setRange(0, mBuffer->size() + size);
477
478 RangeInfo info;
479 info.mLength = size;
480 info.mTimestampUs = timeUs;
481 info.mPesOffset = payloadOffset;
482 info.mPesScramblingControl = pesScramblingControl;
483 mRangeInfos.push_back(info);
484
485#if 0
486 if (mMode == AAC) {
487 ALOGI("size = %zu, timeUs = %.2f secs", size, timeUs / 1E6);
488 hexdump(data, size);
489 }
490#endif
491
492 return OK;
493 }
看似冗长, 其实是case
过多的缘故, 来简单梳理下.
278 - 281: 判断下EOS
;
282 - 456: 如果传入的ABuffer判断为有效的话(mBuffer == NULL || mBuffer->size() == 0
), 根据传入的mMode
(根据stream type定义的), 组织各自类型的结构.
458 - 476: 通过计算neededSize
, 来重新调整ESQueue
所维护的mBuffer
的大小;
478 - 483: 维护RangeInfo
(和pes
有关);
6.3 sp ElementaryStreamQueue::dequeueAccessUnit()
616 sp ElementaryStreamQueue::dequeueAccessUnit() {
617 if ((mFlags & kFlag_AlignedData) && mMode == H264 && !isScrambled()) {
618 if (mRangeInfos.empty()) {
619 return NULL;
620 }
621
622 RangeInfo info = *mRangeInfos.begin();
623 mRangeInfos.erase(mRangeInfos.begin());
624
625 sp accessUnit = new ABuffer(info.mLength);
626 memcpy(accessUnit->data(), mBuffer->data(), info.mLength);
627 accessUnit->meta()->setInt64("timeUs", info.mTimestampUs);
628
629 memmove(mBuffer->data(),
630 mBuffer->data() + info.mLength,
631 mBuffer->size() - info.mLength);
632
633 mBuffer->setRange(0, mBuffer->size() - info.mLength);
634
635 if (mFormat == NULL) {
636 mFormat = MakeAVCCodecSpecificData(accessUnit);
637 }
638
639 return accessUnit;
640 }
641
642 switch (mMode) {
643 case H264:
644 return dequeueAccessUnitH264();
645 case AAC:
646 return dequeueAccessUnitAAC();
647 case AC3:
648 return dequeueAccessUnitAC3();
649 case MPEG_VIDEO:
650 return dequeueAccessUnitMPEGVideo();
651 case MPEG4_VIDEO:
652 return dequeueAccessUnitMPEG4Video();
653 case PCM_AUDIO:
654 return dequeueAccessUnitPCMAudio();
655 case METADATA:
656 return dequeueAccessUnitMetadata();
657 default:
658 if (mMode != MPEG_AUDIO) {
659 ALOGE("Unknown mode");
660 return NULL;
661 }
662 return dequeueAccessUnitMPEGAudio();
663 }
664 }
617 - 640: 如果①. 传入的mFlags
为kFlag_AlignedData
(append到queue中的Data是在边界的). 并且②. 是H264的Video stream. 并且③. 没有加扰. 满足以上3个条件, 就进入这个分支.
642 - 663: 根据mMode
, 分别调用不同stream type的dequeueAccessUnitXXX
;
至此, MPEG2TSExtractor全篇结束. 虽然写的很杂乱, 但是至少是从上到下走了一遍Flow. 如果之后还有更深层的理解, 我再回来慢慢精化.
这篇应该是年前最后一篇文章了吧. 回顾2017, 惊喜/ 兴奋/ 沮丧/ 悲伤五味杂陈. 不过, 无论如何, 总归是佛系过来了, 2018旺旺旺来了, 好运还会远吗? 不会, 它时刻等待着有准备的人去抓住它.
向2017说声走好, 向2018说声我来了~