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