1 /*
2 * Copyright (C) 2017 peak3d
3 * http://www.peak3d.de
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #include "ADTSReader.h"
20 #include "Ap4ByteStream.h"
21 #include <stdlib.h>
22
getSize(const uint8_t * data,unsigned int len,unsigned int shift)23 uint64_t ID3TAG::getSize(const uint8_t *data, unsigned int len, unsigned int shift)
24 {
25 uint64_t size(0);
26 const uint8_t *dataE(data + len);
27 for (; data < dataE; ++data)
28 size = size << shift | *data;
29 return size;
30 };
31
parse(AP4_ByteStream * stream)32 ID3TAG::PARSECODE ID3TAG::parse(AP4_ByteStream *stream)
33 {
34 uint8_t buffer[64];
35 unsigned int retCount(0);
36
37 while (!AP4_SUCCEEDED(stream->Read(buffer, HEADER_SIZE)))
38 {
39 if (retCount++)
40 return PARSE_FAIL;
41 }
42
43 if (memcmp(buffer, "ID3", 3) != 0)
44 {
45 AP4_Position pos;
46 stream->Tell(pos);
47 stream->Seek(pos - HEADER_SIZE);
48 return PARSE_NO_ID3;
49 }
50
51 m_majorVer = buffer[3];
52 m_flags = buffer[5];
53 uint32_t size = static_cast<uint32_t>(getSize(buffer + 6, 4, 7));
54
55 //iterate through frames and search timestamp
56 while (size > HEADER_SIZE)
57 {
58 if (!AP4_SUCCEEDED(stream->Read(buffer, HEADER_SIZE)))
59 return PARSE_FAIL;
60
61 uint32_t frameSize = static_cast<uint32_t>(getSize(buffer + 4, 4, 8));
62
63 if (memcmp(buffer, "PRIV", 4) == 0 && frameSize == 53)
64 {
65 if (!AP4_SUCCEEDED(stream->Read(buffer, frameSize)))
66 return PARSE_FAIL;
67
68 if (strncmp(reinterpret_cast<const char*>(buffer), "com.apple.streaming.transportStreamTimestamp", 44) == 0 && buffer[44] == 0)
69 {
70 m_timestamp = getSize(buffer + 45, 8, 8);
71 }
72 }
73 else
74 {
75 AP4_Position curPos;
76 stream->Tell(curPos);
77 stream->Seek(curPos + frameSize);
78 }
79 size -= (HEADER_SIZE + frameSize);
80 }
81 return PARSE_SUCCESS;
82 }
83
84 /**********************************************************************************************************************************/
85
getBE(const uint8_t * data,unsigned int len)86 uint64_t ADTSFrame::getBE(const uint8_t *data, unsigned int len)
87 {
88 uint64_t size(0);
89 const uint8_t *dataE(data + len);
90 for (; data < dataE; ++data)
91 size = size << 8 | *data;
92 return size;
93 };
94
parse(AP4_ByteStream * stream)95 bool ADTSFrame::parse(AP4_ByteStream *stream)
96 {
97 uint8_t buffer[64];
98
99 static const uint32_t freqTable[13] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350 };
100
101 if (!AP4_SUCCEEDED(stream->Read(buffer, 2)))
102 return false;
103
104 m_outerHeader = static_cast<uint16_t>(getBE(buffer, 2));
105 if ((m_outerHeader & 0xFFF6u) != 0xFFF0u)
106 return false;
107
108 m_innerHeaderSize = (m_outerHeader & 1) ? 7 : 5; // 16 bit CRC
109 if (!AP4_SUCCEEDED(stream->Read(buffer, m_innerHeaderSize)))
110 return false;
111
112 m_innerHeader = getBE(buffer, m_innerHeaderSize);
113 // add 0 crc to have bits on same place for crc / nocrc
114 m_innerHeader <<= ((7 - m_innerHeaderSize) * 8);
115
116 m_totalSize = (m_innerHeader >> 0x1D) & 0x1FFFu;
117 m_frameCount = ((m_innerHeader >> 0x10) & 0x3u) ? 960 : 1024;
118 m_summedFrameCount += m_frameCount;
119 m_sampleRate = (m_innerHeader >> 0x32) & 0xFu;
120 m_sampleRate = (m_sampleRate < 13) ? freqTable[m_sampleRate] : 0;
121 m_channelConfig = (m_innerHeader >> 0x2E) & 0x7u;
122
123 AP4_Position currentPos;
124 stream->Tell(currentPos);
125 stream->Seek(currentPos - (m_innerHeaderSize + 2));
126
127 m_dataBuffer.SetDataSize(m_totalSize);
128 if (!AP4_SUCCEEDED(stream->Read(m_dataBuffer.UseData(), m_dataBuffer.GetDataSize())))
129 return false;
130
131 //ADTS Streams have padding, at EOF
132 AP4_Position pos, posNew;
133 stream->Tell(pos);
134 stream->Seek(pos + 16);
135 stream->Tell(posNew);
136 if (posNew - pos == 16)
137 stream->Seek(pos);
138
139 return true;
140 }
141
142 /**********************************************************************************************************************************/
143
144
ADTSReader(AP4_ByteStream * stream)145 ADTSReader::ADTSReader(AP4_ByteStream *stream)
146 : m_stream(stream)
147 {
148 }
149
~ADTSReader()150 ADTSReader::~ADTSReader()
151 {
152 }
153
Reset()154 void ADTSReader::Reset()
155 {
156 m_pts = ADTS_PTS_UNSET;
157 m_frameParser.reset();
158 }
159
GetInformation(kodi::addon::InputstreamInfo & info)160 bool ADTSReader::GetInformation(kodi::addon::InputstreamInfo& info)
161 {
162 return false;
163 }
164
165 // We assume that m_startpos is the current I-Frame position
SeekTime(uint64_t timeInTs,bool preceeding)166 bool ADTSReader::SeekTime(uint64_t timeInTs, bool preceeding)
167 {
168 while (m_pts < timeInTs)
169 if (!ReadPacket())
170 return false;
171 return true;
172 }
173
ReadPacket()174 bool ADTSReader::ReadPacket()
175 {
176 ID3TAG::PARSECODE id3Ret;
177 while (true)
178 {
179 if ((id3Ret = m_id3TagParser.parse(m_stream)) == ID3TAG::PARSE_SUCCESS)
180 continue;
181 else if (id3Ret == ID3TAG::PARSE_FAIL)
182 break;
183
184 if (m_id3TagParser.getPts(m_basePts))
185 m_frameParser.resetFrameCount();
186
187 m_pts = m_basePts + m_frameParser.getPtsOffset();
188
189 return m_frameParser.parse(m_stream);
190 }
191 return true;
192 }
193