first commit
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# mp4-atom
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Parses iTunes-style metadata from MP4/M4A audio containers by walking the MPEG-4 ISO Base Media box (atom) tree. The parser navigates `moov → udta → meta → ilst` (with a fallback to `moov → meta → ilst` for non-standard files) and decodes all standard iTunes tag atoms into a normalised `Track` record.
|
||||
|
||||
The implementation is pure binary — it uses no external XML or MP4 libraries, operating directly on a `Uint8Array` with the shared `buffer-utils` helpers.
|
||||
|
||||
## Features
|
||||
|
||||
- Generic box/atom tree walker (`iterBoxes`) with graceful handling of corrupted sizes and EOF-marker boxes
|
||||
- Supports both `moov/udta/meta/ilst` and `moov/meta/ilst` layouts
|
||||
- Decodes UTF-8 text atoms: `©nam`, `©ART`, `©alb`, `aART`, `©day`, `©gen`, `©cmt`, `©lyr`
|
||||
- Parses `trkn` and `disk` integer-pair atoms into `trackNumber / totalTracks` and `discNumber / totalDiscs`
|
||||
- Handles `gnre` numeric genre index (1-based ID3v1 list) and `©gen` free-text genre
|
||||
- Cover art extraction from `covr/data` with MIME-type detection (JPEG=0x0d, PNG=0x0e)
|
||||
- Options: `skipCovers`, `maxCoverSize`
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { parseMp4 } from "@suaveplan/audio-metadata/parsers/mp4-atom";
|
||||
|
||||
const track = parseMp4(m4aBuffer);
|
||||
console.log(track.title); // "Bohemian Rhapsody"
|
||||
console.log(track.year); // 1975
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { parseMp4 } from "@suaveplan/audio-metadata/parsers/mp4-atom";
|
||||
|
||||
const track = parseMp4(m4aBuffer, {
|
||||
skipCovers: false,
|
||||
maxCoverSize: 1024 * 1024, // 1 MiB limit
|
||||
});
|
||||
|
||||
if (track.cover) {
|
||||
console.log(track.cover.mimeType); // "image/jpeg" or "image/png"
|
||||
console.log(track.cover.data.length); // bytes
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `parseMp4(buffer, options?)`
|
||||
|
||||
```ts
|
||||
function parseMp4(
|
||||
buffer: Uint8Array,
|
||||
options?: {
|
||||
skipCovers?: boolean;
|
||||
maxCoverSize?: number;
|
||||
},
|
||||
): Track
|
||||
```
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `buffer` | `Uint8Array` | Full MP4/M4A file buffer |
|
||||
| `options.skipCovers` | `boolean` | Skip cover art extraction |
|
||||
| `options.maxCoverSize` | `number` | Maximum cover bytes to accept (default 5 MiB) |
|
||||
|
||||
**Returns:** `Track` object; `{}` if no `ilst` atom is found.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Each MP4 box starts with a 4-byte big-endian size (including the 8-byte header) followed by a 4-byte ASCII type code. A size of `0` means the box extends to the end of the file; a size of `1` means a 64-bit extended size follows — 64-bit boxes are skipped because they are not used for metadata in practice. The `meta` box includes a 4-byte version+flags prefix before its children, which `parseMp4` skips by advancing `dataOffset + 4` before searching for `ilst`. The `©` prefix in atom names (Unicode U+00A9) matches the raw Latin-1 byte `0xa9` written by all major encoders. Track/disc number parsing reads a 6-byte big-endian structure: 2 bytes padding, 2 bytes number, 2 bytes total.
|
||||
Reference in New Issue
Block a user