| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="../../resources/testharness.js"></script> | |
| <script src="../../resources/testharnessreport.js"></script> | |
| </head> | |
| <body> | |
| <script> | |
| // Data offsets for audio-aac.mp4 | |
| // - AudioSpecificConfig (description): offset 1757, size 25 bytes | |
| // - First AAC sample: offset 44, size 28 bytes | |
| // - Sample rate: 48000 Hz | |
| // - Channels: 4 (quad) | |
| // - First sample timestamp: 0 (in 48000 Hz time base) | |
| // - Sample duration: 1024 samples | |
| const descriptionOffset = 1757; | |
| const descriptionSize = 25; | |
| const sampleOffset = 44; | |
| const sampleSize = 28; | |
| const sampleRate = 48000; | |
| const numberOfChannels = 4; | |
| const sampleTimestamp = 0; // in 48000 Hz time base | |
| const sampleDuration = 1024; // in samples | |
| promise_test(async () => { | |
| const response = await fetch("./resources/audio-aac.mp4"); | |
| const buffer = await response.arrayBuffer(); | |
| let decodedFrames = []; | |
| let decodeError = null; | |
| const decoder = new AudioDecoder({ | |
| output(frame) { | |
| decodedFrames.push({ | |
| timestamp: frame.timestamp, | |
| duration: frame.duration, | |
| numberOfFrames: frame.numberOfFrames, | |
| numberOfChannels: frame.numberOfChannels, | |
| sampleRate: frame.sampleRate, | |
| format: frame.format | |
| }); | |
| frame.close(); | |
| }, | |
| error(e) { | |
| decodeError = e; | |
| } | |
| }); | |
| // Configure the decoder with AAC-LC codec and the AudioSpecificConfig from the MP4 file | |
| const description = new Uint8Array(buffer, descriptionOffset, descriptionSize); | |
| decoder.configure({ | |
| codec: 'mp4a.40.2', // AAC-LC | |
| sampleRate: sampleRate, | |
| numberOfChannels: numberOfChannels, | |
| description: description | |
| }); | |
| // Create an EncodedAudioChunk from the first AAC sample | |
| const sampleData = new Uint8Array(buffer, sampleOffset, sampleSize); | |
| // Convert timestamp from 48000 Hz time base to microseconds | |
| const timestampMicroseconds = Math.round((sampleTimestamp / sampleRate) * 1000000); | |
| const durationMicroseconds = Math.round((sampleDuration / sampleRate) * 1000000); | |
| const chunk = new EncodedAudioChunk({ | |
| type: 'key', | |
| timestamp: timestampMicroseconds, | |
| duration: durationMicroseconds, | |
| data: sampleData | |
| }); | |
| decoder.decode(chunk); | |
| await decoder.flush(); | |
| assert_equals(decodeError, null, "No decode error should occur"); | |
| assert_equals(decodedFrames.length, 1, "Should have decoded exactly one frame"); | |
| const frame = decodedFrames[0]; | |
| assert_equals(frame.numberOfChannels, numberOfChannels, "Decoded frame should have correct number of channels"); | |
| assert_equals(frame.sampleRate, sampleRate, "Decoded frame should have correct sample rate"); | |
| assert_equals(frame.numberOfFrames, sampleDuration, "Decoded frame should have correct number of samples"); | |
| assert_equals(frame.timestamp, timestampMicroseconds, "Decoded frame should have correct timestamp"); | |
| decoder.close(); | |
| }, "Decode first AAC sample from MP4 file with extended AudioSpecificConfig"); | |
| </script> | |
| </body> | |
| </html> |