last-frame-dimensions.html (3789B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>Test dimensions of last frame with short frame durations</title> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="mediasource-util.js"></script> 8 </head> 9 <body> 10 </body> 11 <script> 12 const frames_per_keyframe = 10; 13 const default_sample_duration = 512; 14 // The frame rate is very high to test that frame dropping logic does not drop 15 // the final frame, but small enough that "plus 1 microsecond" on "remove 16 // window timestamp" does not cause the first frame to be removed. 17 const fps = 0.5e6; 18 const timescale = default_sample_duration * fps; 19 const earliest_presentation_time = 1024; 20 const frame0_offset = earliest_presentation_time / default_sample_duration; 21 const media_timescale_start = 0x182; 22 const segment_index_timescale_start = 0x353; 23 24 let media_320, media_640; 25 promise_test(async t => { 26 media_320 = await new Promise( 27 r => MediaSourceUtil.fetchManifestAndData( 28 t, 29 `mp4/test-v-128k-320x240-30fps-${frames_per_keyframe}kfr-manifest.json`, 30 (type, data) => r({type, data}))); 31 // Overwrite timescale to shorten frame durations. 32 MediaSourceUtil.WriteBigEndianInteger32ToUint8Array( 33 timescale, media_320.data.subarray(media_timescale_start)); 34 MediaSourceUtil.WriteBigEndianInteger32ToUint8Array( 35 timescale, media_320.data.subarray(segment_index_timescale_start)); 36 37 media_640 = await new Promise( 38 r => MediaSourceUtil.fetchManifestAndData( 39 t, 40 `mp4/test-v-128k-640x480-30fps-${frames_per_keyframe}kfr-manifest.json`, 41 (type, data) => r({type, data}))); 42 // Overwrite timescale to shorten frame durations. 43 MediaSourceUtil.WriteBigEndianInteger32ToUint8Array( 44 timescale, media_640.data.subarray(media_timescale_start)); 45 MediaSourceUtil.WriteBigEndianInteger32ToUint8Array( 46 timescale, media_640.data.subarray(segment_index_timescale_start)); 47 }, 'setup'); 48 49 promise_test(async t => { 50 assert_implements_optional(MediaSource.isTypeSupported(media_320.type), 51 'type supported'); 52 53 const v = document.createElement('video'); 54 const v_watcher = new EventWatcher(t, v, ['error', 'ended']); 55 document.body.appendChild(v); 56 const media_source = new MediaSource(); 57 const media_source_watcher = 58 new EventWatcher(t, media_source, ['sourceopen']); 59 v.src = URL.createObjectURL(media_source); 60 await media_source_watcher.wait_for('sourceopen'); 61 62 const source_buffer = media_source.addSourceBuffer(media_320.type); 63 assert_equals(source_buffer.mode, 'segments', 'source_buffer.mode'); 64 const source_buffer_watcher = 65 new EventWatcher(t, source_buffer, ['updateend']); 66 67 // Append the first 320x240 frame. 68 source_buffer.appendWindowEnd = (frame0_offset + 1) / fps; 69 source_buffer.appendBuffer(media_320.data); 70 await source_buffer_watcher.wait_for('updateend'); 71 assert_true(true, 'updateend'); 72 73 // Append the first 640x480 frame. 74 source_buffer.timestampOffset = 1 / fps; 75 source_buffer.appendWindowEnd = (1 + frame0_offset + 1) / fps; 76 source_buffer.appendBuffer(media_640.data); 77 // Not using v_watcher to work around an extra canplaythrough from Chrome. 78 const canplaythrough_promise = new Promise(r => v.oncanplaythrough = r); 79 await source_buffer_watcher.wait_for('updateend'); 80 81 media_source.endOfStream(); 82 await canplaythrough_promise; 83 assert_equals(v.videoWidth, 320, 'videoWidth 320'); 84 assert_approx_equals(v.duration, 85 source_buffer.appendWindowEnd, 86 1e-6, 87 'duration'); 88 89 v.play(); 90 await v_watcher.wait_for('ended'); 91 assert_equals(v.currentTime, v.duration, 'v.currentTime'); 92 assert_equals(v.videoWidth, 640, 'videoWidth 640'); 93 }, 'last frame dimensions'); 94 </script> 95 </html>