Write out audio metadata frequently. Fixes #169.
If the source was switched among variant playlists that have different audio sampling rates and the initial audio metadata tag skipped, audio would dissapear. Instead, emit an audio meta tag at least once per second so that the decoder can get back on track after a change. Fix typo that caused audio DTS not to be written out properly.
Showing
2 changed files
with
26 additions
and
5 deletions
... | @@ -23,6 +23,7 @@ window.videojs.Hls.AacStream = function() { | ... | @@ -23,6 +23,7 @@ window.videojs.Hls.AacStream = function() { |
23 | pts_offset, // :int | 23 | pts_offset, // :int |
24 | state, // :uint | 24 | state, // :uint |
25 | pes_length, // :int | 25 | pes_length, // :int |
26 | lastMetaPts, | ||
26 | 27 | ||
27 | adtsProtectionAbsent, // :Boolean | 28 | adtsProtectionAbsent, // :Boolean |
28 | adtsObjectType, // :int | 29 | adtsObjectType, // :int |
... | @@ -43,6 +44,11 @@ window.videojs.Hls.AacStream = function() { | ... | @@ -43,6 +44,11 @@ window.videojs.Hls.AacStream = function() { |
43 | // on the first invocation, capture the starting PTS value | 44 | // on the first invocation, capture the starting PTS value |
44 | pts_offset = pts; | 45 | pts_offset = pts; |
45 | 46 | ||
47 | // keep track of the last time a metadata tag was written out | ||
48 | // set the initial value so metadata will be generated before any | ||
49 | // payload data | ||
50 | lastMetaPts = pts - 1000; | ||
51 | |||
46 | // on subsequent invocations, calculate the PTS based on the starting offset | 52 | // on subsequent invocations, calculate the PTS based on the starting offset |
47 | this.setNextTimeStamp = function(pts, pes_size, dataAligned) { | 53 | this.setNextTimeStamp = function(pts, pes_size, dataAligned) { |
48 | next_pts = pts - pts_offset; | 54 | next_pts = pts - pts_offset; |
... | @@ -157,7 +163,11 @@ window.videojs.Hls.AacStream = function() { | ... | @@ -157,7 +163,11 @@ window.videojs.Hls.AacStream = function() { |
157 | newExtraData = (adtsObjectType << 11) | | 163 | newExtraData = (adtsObjectType << 11) | |
158 | (adtsSampleingIndex << 7) | | 164 | (adtsSampleingIndex << 7) | |
159 | (adtsChanelConfig << 3); | 165 | (adtsChanelConfig << 3); |
160 | if (newExtraData !== extraData) { | 166 | |
167 | // write out metadata tags every 1 second so that the decoder | ||
168 | // is re-initialized quickly after seeking into a different | ||
169 | // audio configuration | ||
170 | if (newExtraData !== extraData || next_pts - lastMetaPts >= 1000) { | ||
161 | aacFrame = new FlvTag(FlvTag.METADATA_TAG); | 171 | aacFrame = new FlvTag(FlvTag.METADATA_TAG); |
162 | aacFrame.pts = next_pts; | 172 | aacFrame.pts = next_pts; |
163 | aacFrame.dts = next_pts; | 173 | aacFrame.dts = next_pts; |
... | @@ -173,16 +183,19 @@ window.videojs.Hls.AacStream = function() { | ... | @@ -173,16 +183,19 @@ window.videojs.Hls.AacStream = function() { |
173 | 183 | ||
174 | extraData = newExtraData; | 184 | extraData = newExtraData; |
175 | aacFrame = new FlvTag(FlvTag.AUDIO_TAG, true); | 185 | aacFrame = new FlvTag(FlvTag.AUDIO_TAG, true); |
176 | aacFrame.pts = aacFrame.dts; | ||
177 | // For audio, DTS is always the same as PTS. We want to set the DTS | 186 | // For audio, DTS is always the same as PTS. We want to set the DTS |
178 | // however so we can compare with video DTS to determine approximate | 187 | // however so we can compare with video DTS to determine approximate |
179 | // packet order | 188 | // packet order |
180 | aacFrame.pts = next_pts; | 189 | aacFrame.pts = next_pts; |
190 | aacFrame.dts = aacFrame.pts; | ||
191 | |||
181 | aacFrame.view.setUint16(aacFrame.position, newExtraData); | 192 | aacFrame.view.setUint16(aacFrame.position, newExtraData); |
182 | aacFrame.position += 2; | 193 | aacFrame.position += 2; |
183 | aacFrame.length = Math.max(aacFrame.length, aacFrame.position); | 194 | aacFrame.length = Math.max(aacFrame.length, aacFrame.position); |
184 | 195 | ||
185 | this.tags.push(aacFrame); | 196 | this.tags.push(aacFrame); |
197 | |||
198 | lastMetaPts = next_pts; | ||
186 | } | 199 | } |
187 | 200 | ||
188 | // Skip the checksum if there is one | 201 | // Skip the checksum if there is one | ... | ... |
... | @@ -341,14 +341,22 @@ | ... | @@ -341,14 +341,22 @@ |
341 | currentPts = tag.pts; | 341 | currentPts = tag.pts; |
342 | 342 | ||
343 | // generic flv headers | 343 | // generic flv headers |
344 | ok(type === 8 || type === 9 || type === 18, | 344 | switch (type) { |
345 | 'the type field specifies audio, video or script'); | 345 | case 8: ok(true, 'the type is audio'); |
346 | break; | ||
347 | case 9: ok(true, 'the type is video'); | ||
348 | break; | ||
349 | case 18: ok(true, 'the type is script'); | ||
350 | break; | ||
351 | default: ok(false, 'the type (' + type + ') is unrecognized'); | ||
352 | } | ||
346 | 353 | ||
347 | byte = (tag.view.getUint32(1) & 0xFFFFFF00) >>> 8; | 354 | byte = (tag.view.getUint32(1) & 0xFFFFFF00) >>> 8; |
348 | equal(tag.bytes.byteLength - 11 - 4, byte, 'the size field is correct'); | 355 | equal(tag.bytes.byteLength - 11 - 4, byte, 'the size field is correct'); |
349 | 356 | ||
350 | byte = tag.view.getUint32(5) & 0xFFFFFF00; | 357 | byte = tag.view.getUint32(5) & 0xFFFFFF00; |
351 | ok(byte >= lastTime, 'the timestamp for the tag is greater than zero'); | 358 | ok(byte >= lastTime, |
359 | 'timestamp is increasing. last pts: ' + lastTime + ' this pts: ' + byte); | ||
352 | lastTime = byte; | 360 | lastTime = byte; |
353 | 361 | ||
354 | // tag type-specific headers | 362 | // tag type-specific headers | ... | ... |
-
Please register or sign in to post a comment