| 182 | } |
| 183 | |
| 184 | decode(payload) { |
| 185 | let parser = new H264Parser(payload); |
| 186 | let result = null; |
| 187 | |
| 188 | // Ideally, this timestamp should come from the server, but we'll just |
| 189 | // approximate it instead. |
| 190 | let timestamp = Math.round(window.performance.now() * 1e3); |
| 191 | |
| 192 | while (true) { |
| 193 | let encodedFrame = parser.parse(); |
| 194 | if (encodedFrame === null) { |
| 195 | break; |
| 196 | } |
| 197 | |
| 198 | if (parser.profileIdc !== null) { |
| 199 | self._profileIdc = parser.profileIdc; |
| 200 | self._constraintSet = parser.constraintSet; |
| 201 | self._levelIdc = parser.levelIdc; |
| 202 | } |
| 203 | |
| 204 | if (this._decoder === null || this._decoder.state !== 'configured') { |
| 205 | if (!encodedFrame.key) { |
| 206 | Log.Warn("Missing key frame. Can't decode until one arrives"); |
| 207 | continue; |
| 208 | } |
| 209 | if (self._profileIdc === null) { |
| 210 | Log.Warn('Cannot config decoder. Have not received SPS and PPS yet.'); |
| 211 | continue; |
| 212 | } |
| 213 | this._configureDecoder(self._profileIdc, self._constraintSet, |
| 214 | self._levelIdc); |
| 215 | } |
| 216 | |
| 217 | result = this._preparePendingFrame(timestamp); |
| 218 | |
| 219 | const chunk = new EncodedVideoChunk({ |
| 220 | timestamp: timestamp, |
| 221 | type: encodedFrame.key ? 'key' : 'delta', |
| 222 | data: encodedFrame.frame, |
| 223 | }); |
| 224 | |
| 225 | try { |
| 226 | this._decoder.decode(chunk); |
| 227 | } catch (e) { |
| 228 | Log.Warn("Failed to decode:", e); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | // We only keep last frame of each payload |
| 233 | if (result !== null) { |
| 234 | result.keep = true; |
| 235 | } |
| 236 | |
| 237 | return result; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | export default class H264Decoder { |