// Get probed metadata (before container)let mut probed_metadata = probed.metadata;if let Some(mut metadata) = probed_metadata.get() { if let Some(rev) = metadata.current() { // Iterate over tags for tag in rev.tags() { println!("{}={}", tag.key, tag.value); } // Access album art for visual in rev.visuals() { println!("Found visual: {} bytes", visual.data.len()); } }}
3
Get format reader metadata
// Get metadata from the container itselflet mut format = probed.format;let mut container_metadata = format.metadata();if let Some(rev) = container_metadata.current() { // Process container metadata for tag in rev.tags() { println!("Container tag: {}={}", tag.key, tag.value); }}
Probed metadata typically contains format-agnostic tags (like ID3v2), while container metadata contains format-specific information.
use symphonia::core::meta::MetadataRevision;// Check if there are newer revisionswhile !format.metadata().is_latest() { // Pop the old revision let old_rev: Option<MetadataRevision> = format.metadata().pop(); // The current revision is now the next one if let Some(current) = format.metadata().current() { // Process updated metadata }}
Metadata revisions should be treated as upserts (update or insert):
// Example: Merging revisionsuse std::collections::HashMap;use symphonia::core::meta::{StandardTagKey, Tag};let mut tags: HashMap<StandardTagKey, String> = HashMap::new();// Process initial revisionif let Some(rev) = format.metadata().current() { for tag in rev.tags() { if let Some(std_key) = tag.std_key { tags.insert(std_key, tag.value.to_string()); } }}// Update with new revisionswhile !format.metadata().is_latest() { format.metadata().pop(); if let Some(rev) = format.metadata().current() { for tag in rev.tags() { if let Some(std_key) = tag.std_key { // Update or insert tags.insert(std_key, tag.value.to_string()); } } }}
Only discard all previous metadata when Error::ResetRequired is returned, as this indicates a complete stream change.
use symphonia::core::meta::{ColorMode, Visual};fn process_visual(visual: &Visual) { println!("Format: {}", visual.media_type); // Bits per pixel (hint only) if let Some(bpp) = visual.bits_per_pixel { println!("Bits per pixel: {}", bpp); } // Color mode if let Some(color_mode) = visual.color_mode { match color_mode { ColorMode::Discrete => { println!("Direct color"); } ColorMode::Indexed(num_colors) => { println!("Indexed color, {} colors", num_colors); } } } // Visual can have its own tags for tag in &visual.tags { println!("Visual tag: {}={}", tag.key, tag.value); }}
Visual dimensions, bit depth, and color mode are hints from metadata and may not match the actual image data. Always validate by decoding the image.
Metadata can be updated while decoding. Check regularly in your decode loop:
use symphonia::core::errors::Error;loop { // Get next packet let packet = match format.next_packet() { Ok(packet) => packet, Err(Error::ResetRequired) => { // Complete reset - discard all metadata unimplemented!(); } Err(err) => break, }; // Check for metadata updates while !format.metadata().is_latest() { // Remove old revision format.metadata().pop(); // Process new revision if let Some(rev) = format.metadata().current() { println!("Metadata updated!"); // Update UI, etc. for tag in rev.tags() { if let Some(std_key) = tag.std_key { // Handle updated tags } } } } // Filter and decode packet // ...}