Skip to content

Commit

Permalink
hacky seeking for m4a and aac
Browse files Browse the repository at this point in the history
  • Loading branch information
aschey committed May 16, 2021
1 parent ec899bf commit 47b039c
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 7 deletions.
4 changes: 4 additions & 0 deletions symphonia-bundle-flac/src/demuxer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ impl FormatReader for FlacReader {
&self.streams
}

fn into_inner(self: Box<Self>) -> MediaSourceStream {
self.reader
}

fn seek(&mut self, to: SeekTo) -> Result<SeekedTo> {
if self.streams.is_empty() {
return seek_error(SeekErrorKind::Unseekable);
Expand Down
4 changes: 4 additions & 0 deletions symphonia-bundle-mp3/src/demuxer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ impl FormatReader for Mp3Reader {
&self.streams
}

fn into_inner(self: Box<Self>) -> MediaSourceStream {
self.reader
}

fn seek(&mut self, to: SeekTo) -> Result<SeekedTo> {
// Get the timestamp of the desired audio frame.
let desired_ts = match to {
Expand Down
49 changes: 46 additions & 3 deletions symphonia-codec-aac/src/adts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_core::support_format;
use std::io::{Seek, SeekFrom};

use symphonia_core::{
errors::{seek_error, SeekErrorKind},
support_format,
};

use symphonia_core::audio::Channels;
use symphonia_core::codecs::{CodecParameters, CODEC_TYPE_AAC};
Expand Down Expand Up @@ -159,7 +164,45 @@ impl FormatReader for AdtsReader {
&self.streams
}

fn seek(&mut self, _to: SeekTo) -> Result<SeekedTo> {
unimplemented!();
fn into_inner(self: Box<Self>) -> MediaSourceStream {
self.reader
}

// Brute force seek attempt. Unsure if this actually works.
fn seek(&mut self, to: SeekTo) -> Result<SeekedTo> {
let desired_ts = match to {
// Frame timestamp given.
SeekTo::TimeStamp { ts, .. } => ts,
// Time value given, calculate frame timestamp from sample rate.
SeekTo::Time { time } => {
// Use the sample rate to calculate the frame timestamp. If sample rate is not
// known, the seek cannot be completed.
if let Some(sample_rate) = self.streams[0].codec_params.sample_rate {
TimeBase::new(1, sample_rate).calc_timestamp(time)
} else {
return seek_error(SeekErrorKind::Unseekable);
}
}
};
self.reader.seek(SeekFrom::Start(0)).unwrap();

let actual_ts: u64;
let mut accum: u64 = 0;
loop {
let next = self.next_packet().unwrap();
accum += (next.buf().len()
* (self.streams[0].codec_params.channels.unwrap().count() + 1))
as u64;

if accum >= desired_ts {
actual_ts = accum as u64;
break;
}
}

Ok(SeekTo::TimeStamp {
ts: actual_ts,
stream: 0,
})
}
}
2 changes: 2 additions & 0 deletions symphonia-core/src/formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ pub trait FormatReader {

/// Get the next packet from the container.
fn next_packet(&mut self) -> Result<Packet>;

fn into_inner(self: Box<Self>) -> MediaSourceStream;
}

/// A `Packet` contains a discrete amount of encoded data for a single codec bitstream. The exact
Expand Down
57 changes: 54 additions & 3 deletions symphonia-format-isomp4/src/demuxer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_core::{errors::end_of_stream_error, support_format};
use symphonia_core::{
errors::{end_of_stream_error, seek_error, SeekErrorKind},
support_format,
};

use symphonia_core::codecs::{CodecParameters, CODEC_TYPE_AAC};
use symphonia_core::errors::{decode_error, unsupported_error, Result};
Expand Down Expand Up @@ -473,7 +476,55 @@ impl FormatReader for IsoMp4Reader {
&self.streams
}

fn seek(&mut self, _to: SeekTo) -> Result<SeekedTo> {
unsupported_error("seeking unsupported")
fn into_inner(self: Box<Self>) -> MediaSourceStream {
self.iter.into_inner()
}

// Brute force seek attempt. This can cause issues when decoding the next sample sometimes so the next sample will need to be skipped in that case
fn seek(&mut self, to: SeekTo) -> Result<SeekedTo> {
let desired_ts = match to {
// Frame timestamp given.
SeekTo::TimeStamp { ts, .. } => ts,
// Time value given, calculate frame timestamp from sample rate.
SeekTo::Time { time } => {
// Use the sample rate to calculate the frame timestamp. If sample rate is not
// known, the seek cannot be completed.
if let Some(sample_rate) = self.streams[0].codec_params.sample_rate {
TimeBase::new(1, sample_rate).calc_timestamp(time)
} else {
return seek_error(SeekErrorKind::Unseekable);
}
}
};
let next_sample_info = loop {
// Using the current set of segments, try to get the next sample info.
if let Some(info) = self.next_sample_info()? {
break info;
} else {
// No more segments. If the stream is unseekable, it may be the case that there are
// more segments coming. Iterate atoms until a new segment is found or the
// end-of-stream is reached.
self.try_read_more_segments()?;
}
};
if next_sample_info.ts >= desired_ts {
let mut track = &mut self.tracks[0];
track.next_sample = 0;
track.next_sample_pos = 0;
}
let actual_ts: u64;
loop {
let next = self.next_packet().unwrap();
let pts = next.pts();
if pts >= desired_ts {
actual_ts = pts;
break;
}
}

Ok(SeekTo::TimeStamp {
ts: actual_ts,
stream: 0,
})
}
}
4 changes: 4 additions & 0 deletions symphonia-format-ogg/src/demuxer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ impl FormatReader for OggReader {
&self.streams
}

fn into_inner(self: Box<Self>) -> MediaSourceStream {
self.reader
}

fn seek(&mut self, _to: SeekTo) -> Result<SeekedTo> {
unsupported_error("ogg seeking unsupported")
}
Expand Down
4 changes: 4 additions & 0 deletions symphonia-format-wav/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ impl FormatReader for WavReader {
&self.streams
}

fn into_inner(self: Box<Self>) -> MediaSourceStream {
self.reader
}

fn seek(&mut self, to: SeekTo) -> Result<SeekedTo> {
if self.streams.is_empty() || self.frame_len == 0 {
return seek_error(SeekErrorKind::Unseekable);
Expand Down
3 changes: 2 additions & 1 deletion symphonia-play/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ mod cpal {
use symphonia::core::conv::ConvertibleSample;
use symphonia::core::units::Duration;

use cpal;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::{self, BufferSize};
use rb::*;

use log::error;
Expand Down Expand Up @@ -199,6 +199,7 @@ mod cpal {
let config = cpal::StreamConfig {
channels: spec.channels.count() as cpal::ChannelCount,
sample_rate: cpal::SampleRate(spec.rate),
buffer_size: BufferSize::Default,
};

// Instantiate a ring buffer capable of buffering 8K (arbitrarily chosen) samples.
Expand Down

0 comments on commit 47b039c

Please sign in to comment.