Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example to use the crate. #1

Closed
sak96 opened this issue Mar 13, 2023 · 12 comments
Closed

Example to use the crate. #1

sak96 opened this issue Mar 13, 2023 · 12 comments

Comments

@sak96
Copy link

sak96 commented Mar 13, 2023

I want to read frame from tcp stream. how to use the crate to do the same ?

I don't see any struct or new method which might be helpful for the same.

@Wicpar
Copy link
Owner

Wicpar commented Mar 13, 2023

there is currently no easy way to read, you have to do it a bit manually, unfortunately the project was put on hold before i got there.

You ned two things: A reader that is AsyncRead + AsyncSeek + Unpin + Send + Sync like an AsyncSTD cursor
and then simply:

let header = BoxHeader::read(&mut reader).await?; // The Mp4Readable read
let ftyp = FtypBox::read(header, &mut reader).await?; // The BoxRead trait read
// read other boxes like the previous, ideally with an enum based on the ID of what you expect.

one of the tests goes like this:

          let base = Box::default();
          let mut buf = vec![];
          let mut cursor = std::io::Cursor::new(&mut buf);
          let pos = base.write(&mut cursor)?;
          assert_eq!(pos, base.byte_size());
          assert_eq!(pos as u64, cursor.position());
          let mut cursor = futures::io::Cursor::new(&mut buf);
          let header = BoxHeader::read(&mut cursor).await?;
          assert_eq!(header.id, Box::ID);
          let new = Box::read(header, &mut cursor).await?;
          assert_eq!(base, new);
          Ok(())

Creating a proper easy to use reader wouldn't be too complicated, either with dyn Any + Other traits, or an enum. That would be a great PR if it's something you enjoy :)

@sak96
Copy link
Author

sak96 commented Mar 13, 2023

Hi,

Thanks for reply.
I will go through the test cases then.
I am not in good term with trait, but i can try that is, if i am comfortable

@sak96
Copy link
Author

sak96 commented Mar 13, 2023

my reader was std::net::TcpStream i moved to use futures_net::TcpStream.
But that one implements futures_io::AsyncRead and not futures::io::AsyncRead.
Do you have any idea of crate which has TcpStream and implements futures::AsyncRead and is lightweight.

@Wicpar
Copy link
Owner

Wicpar commented Mar 13, 2023

You have async_std::net::TcpStream, but since you need seek wrap it in a async_std::io::BufReader.
You may also need to pin it, in that case use Box::pin()
Hope it helps :)

@sak96
Copy link
Author

sak96 commented Mar 14, 2023

Hey i think i am getting hang of stuff now.

Looks like Bufreader doesn't provide asyncSeek.
i am assuming seek if like fseek systemcall.

The issue i see is that there is no way of know how much buffer is required.
you might do seek of 0 that means go to the beginning of stream.
Do i have to store all the data from start of stream ?

@Wicpar
Copy link
Owner

Wicpar commented Mar 14, 2023

In principle, to be sure you can parse all kinds of MP4 you need to store the whole stream, even if you can start parsing before the end. But if you know where the mdats are and store the data separately with their proper offsets like in a fragmented mp4 then you don't really need to seek i think.
Maybe it would be wise to create a reader made for the use. To be fair i didn't use the read part of the library much, i mostly used it to convert from mkv to mp4.

@Wicpar
Copy link
Owner

Wicpar commented Mar 14, 2023

ah i see, here is the use:
it's quite necessary to keep track of the position...

#[async_trait]
impl<P> BoxRead for MP4Box<P>
where
P: PartialBox<ParentData=()> + PartialBoxRead + Send + Sync,
{
async fn read<R: ReadMp4>(header: BoxHeader, reader: &mut R) -> Result<Self, MP4Error> {
let actual = header.id;
let target = Self::ID;
if actual != target {
return Err(ReadingWrongBox {actual, target}.into())
}
let start = reader.seek(SeekFrom::Current(0)).await? - header.byte_size() as u64;
let size = header.size;
let mut inner = P::read_data((), reader).await?;
while !size.ended(start, reader).await? {
let header: BoxHeader = reader.read().await?;
let pos = reader.seek(SeekFrom::Current(0)).await?;
let size = header.size_minus_self();
inner.read_child(header, reader).await?;
if let Known(size) = size { // we do the check here because it's far safer
reader.seek(SeekFrom::Start(pos + size as u64)).await?;
} else {
return Err(UnknownSizeForUnknownBox.into());
}
}
Ok(Self { inner })
}
}

@Wicpar
Copy link
Owner

Wicpar commented Mar 14, 2023

To be fair, reading linearly could still be possible, but a bug in one of the boxes implementation could corrupt the whole parsing...
I deemed it too much of a risk back then, but seek is indeed quite a constraint, maybe it's time to rework that...

@Wicpar
Copy link
Owner

Wicpar commented Mar 14, 2023

futures::io::BufReader is AsyncRead and AsyncSeek

@sak96
Copy link
Author

sak96 commented Mar 15, 2023

The AsyncSeek is only implemented if it also exists for inner Type R.
The TcpStream doesn't impl AsyncSeek.

https://github.com/rust-lang/futures-rs/blob/4e210b8cedc2fda2e3c8b8a1aab93e4c668ba9af/futures-util/src/io/buf_reader.rs#L178

What is see is the if the data is stored for header size then we don't really need seek.
Will try to see if the seek can be avoided.

Can you explain PartialBoxRead Trait ?

May be you are write mp4 cannot be streamable. alfg/mp4-rust#53

@Wicpar
Copy link
Owner

Wicpar commented Mar 15, 2023

if we implement things around a content aware context it should be possible to stream. Seek isn't used very often, it's mostly used to make sure there are no mistakes.
To bad for the seek, didn't see the constraint :/
for the PartialBoxRead, it is necessary for PartialBox, which handles the inheritance of the boxes. Full box is the final form of a complete box. The partialBoxRead needs to read the header and the data separately as it may be split depending on the parent, where the fullBox always is sequential.

@sak96
Copy link
Author

sak96 commented Mar 18, 2023

I just went through this video looks like there is lot of stuff to video decoding.

Will close this issue as i am not going to pick this immediate but thanks for the guidance was really helpful.

@sak96 sak96 closed this as completed Mar 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants