aae7a508 by David LaPalomento

Close off all FLV tags at the end of a segment

The segment parser allows fragmentary input to the muxing process so it's not always clear when a tag should be finalized at the end of the input. By calling segmentParser.flushTags(), the parser is instructed to wrap up whatever input it currently has buffered into an FLV tag. Before this change, the last tag of the video stream would be buffered in the parser, waiting for additional input (i.e. another segment download) to flush it out. When you seeked within a segment, that last tag would have a timestamp greater than your seek point and we were assuming that timestamp values were sorted in ascending order. We would see the timestamp value greater than the desired seek location and start feeding tags into the media source, which resulted in the segment appearing to restart. Now, we close off any tags that are buffered at the end of a segment so the inter-segment seeking routine can assume that tags are delivered in the order of playback.
1 parent 216ff405
...@@ -292,7 +292,7 @@ ...@@ -292,7 +292,7 @@
292 292
293 //(pts:uint, dts:uint, dataAligned:Boolean):void 293 //(pts:uint, dts:uint, dataAligned:Boolean):void
294 this.setNextTimeStamp = function(pts, dts, dataAligned) { 294 this.setNextTimeStamp = function(pts, dts, dataAligned) {
295 if (0>pts_delta) { 295 if (pts_delta < 0) {
296 // We assume the very first pts is less than 0x8FFFFFFF (max signed 296 // We assume the very first pts is less than 0x8FFFFFFF (max signed
297 // int32) 297 // int32)
298 pts_delta = pts; 298 pts_delta = pts;
...@@ -310,7 +310,7 @@ ...@@ -310,7 +310,7 @@
310 310
311 this.finishFrame = function() { 311 this.finishFrame = function() {
312 if (h264Frame) { 312 if (h264Frame) {
313 // Push SPS before EVERY IDR frame fo seeking 313 // Push SPS before EVERY IDR frame for seeking
314 if (newExtraData.extraDataExists()) { 314 if (newExtraData.extraDataExists()) {
315 oldExtraData = newExtraData; 315 oldExtraData = newExtraData;
316 newExtraData = new H264ExtraData(); 316 newExtraData = new H264ExtraData();
......
...@@ -358,9 +358,6 @@ ...@@ -358,9 +358,6 @@
358 offset += pesHeaderLength; 358 offset += pesHeaderLength;
359 359
360 if (pid === self.stream.programMapTable[STREAM_TYPES.h264]) { 360 if (pid === self.stream.programMapTable[STREAM_TYPES.h264]) {
361 // Stash this frame for future use.
362 // console.assert(videoFrames.length < 3);
363
364 h264Stream.setNextTimeStamp(pts, 361 h264Stream.setNextTimeStamp(pts,
365 dts, 362 dts,
366 dataAlignmentIndicator); 363 dataAlignmentIndicator);
......
...@@ -293,8 +293,8 @@ var ...@@ -293,8 +293,8 @@ var
293 293
294 sortedPlaylists.sort(playlistBandwidth); 294 sortedPlaylists.sort(playlistBandwidth);
295 295
296 // map playlist options by bandwidth and select 296 // filter out any variant that has greater effective bitrate
297 // best variant as appropriate 297 // than the current estimated bandwidth
298 while (i--) { 298 while (i--) {
299 variant = sortedPlaylists[i]; 299 variant = sortedPlaylists[i];
300 300
...@@ -305,39 +305,36 @@ var ...@@ -305,39 +305,36 @@ var
305 305
306 effectiveBitrate = variant.attributes.BANDWIDTH * bandwidthVariance; 306 effectiveBitrate = variant.attributes.BANDWIDTH * bandwidthVariance;
307 307
308 // since the playlists are sorted in ascending order by bandwidth, the
309 // current variant is the best as long as its effective bitrate is
310 // below the current bandwidth estimate
311 // NOTE - only set once
312 if (effectiveBitrate < player.hls.bandwidth) { 308 if (effectiveBitrate < player.hls.bandwidth) {
313 bandwidthPlaylists.push(variant); 309 bandwidthPlaylists.push(variant);
310
311 // since the playlists are sorted in ascending order by
312 // bandwidth, the first viable variant is the best
314 if (!bandwidthBestVariant) { 313 if (!bandwidthBestVariant) {
315 bandwidthBestVariant = variant; 314 bandwidthBestVariant = variant;
316 } 315 }
317 } 316 }
318 } 317 }
319 318
320 // set index to the available bandwidth mapped renditions
321 i = bandwidthPlaylists.length; 319 i = bandwidthPlaylists.length;
322 320
323 // sort those by resolution [currently widths] 321 // sort variants by resolution
324 bandwidthPlaylists.sort(playlistResolution); 322 bandwidthPlaylists.sort(playlistResolution);
325 323
326 // iterate through bandwidth related playlists and find 324 // iterate through the bandwidth-filtered playlists and find
327 // best rendition by player dimension 325 // best rendition by player dimension
328
329 // Tests
330 // Seeking - find if you've seeked correctly?
331 // SelectPlaylist -
332 while (i--) { 326 while (i--) {
333 variant = bandwidthPlaylists[i]; 327 variant = bandwidthPlaylists[i];
334 328
335 // ignored playlists without resolution information 329 // ignore playlists without resolution information
336 if (!variant.attributes || !variant.attributes.RESOLUTION || 330 if (!variant.attributes || !variant.attributes.RESOLUTION ||
337 !variant.attributes.RESOLUTION.width || !variant.attributes.RESOLUTION.height) { 331 !variant.attributes.RESOLUTION.width || !variant.attributes.RESOLUTION.height) {
338 continue; 332 continue;
339 } 333 }
340 334
335 // since the playlists are sorted, the first variant that has
336 // dimensions less than or equal to the player size is the
337 // best
341 if (variant.attributes.RESOLUTION.width <= player.width() && 338 if (variant.attributes.RESOLUTION.width <= player.width() &&
342 variant.attributes.RESOLUTION.height <= player.height()) { 339 variant.attributes.RESOLUTION.height <= player.height()) {
343 resolutionBestVariant = variant; 340 resolutionBestVariant = variant;
...@@ -526,13 +523,13 @@ var ...@@ -526,13 +523,13 @@ var
526 523
527 // transmux the segment data from MP2T to FLV 524 // transmux the segment data from MP2T to FLV
528 segmentParser.parseSegmentBinaryData(new Uint8Array(this.response)); 525 segmentParser.parseSegmentBinaryData(new Uint8Array(this.response));
526 segmentParser.flushTags();
529 527
530 // if we're refilling the buffer after a seek, scan through the muxed 528 // if we're refilling the buffer after a seek, scan through the muxed
531 // FLV tags until we find the one that is closest to the desired 529 // FLV tags until we find the one that is closest to the desired
532 // playback time 530 // playback time
533 if (offset !== undefined && typeof offset === "number") { 531 if (offset !== undefined && typeof offset === "number") {
534 while (segmentParser.getTags()[0].pts < offset) { 532 while (segmentParser.getTags()[0].pts < offset) {
535 // we're seeking past this tag, so ignore it
536 segmentParser.getNextTag(); 533 segmentParser.getNextTag();
537 } 534 }
538 } 535 }
......