zmwangx / rust-ffmpeg

Safe FFmpeg wrapper.
Do What The F*ck You Want To Public License
1.27k stars 202 forks source link

anyone has sucess decoding .h264 / av_parser_parse2 really needed? #35

Open lattice0 opened 3 years ago

lattice0 commented 3 years ago

I'm trying to decode a video in .h264. On C++ I could simply make the pointer inside the AvPacket point to my chunk of h264 data and it'd work. On Rust, since it copies to AvPacket instead of setting pointer, I don't know but I'm not being able to decode. I get:

[h264 @ 0x587c784f6640] Frame num change from 11 to 12
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] Frame num change from 12 to 13
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] Frame num change from 12 to 13
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] Frame num change from 12 to 13
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] Frame num change from 14 to 15
[h264 @ 0x587c784f6640] decode_slice_header error

Well, on the official .c examples, they use av_parser_parse2 to parse the packet before sending it.

Did anyone have success decoding video, specially in .h264 raw stream? I'm using the new send_packet/receive_frame. Is av_parser_parse2 really needed?

It looks like there's no av_parser_parse2 in rust-ffmpeg. I can add it, but where should I add exactly?

lattice0 commented 3 years ago

I created the parse2 function: https://github.com/zmwangx/rust-ffmpeg/compare/master...lucaszanella:master but it's a sketch, I didn't even run it yet.

That's because av_parser_parse2 expects you to pass pointers, then advance them. I'm thinking of a safe way to advance the slice to call av_parser_parse2.

@zmwangx, what you think of the place where I placed the parse2 function? Do you have any ideas?

Thanks!

lattice0 commented 3 years ago

I'm also adding support for compilating against ffmpeg with vdpau, which also have some modificaitons on the rust-ffmpeg-sys repo, I'll post later. That's why there's some stuff on build.rs

zmwangx commented 3 years ago

I'm trying to decode a video in .h264. On C++ I could simply make the pointer inside the AvPacket point to my chunk of h264 data and it'd work. On Rust, since it copies to AvPacket instead of setting pointer, I don't know but I'm not being able to decode.

...

Is av_parser_parse2 really needed?

If your stream is delimited, you can simply use Packet::copy as I demonstrated in #29 (sample code). If not and you absolutely can't use facilities provided by lavf which handles parsing for you, then I suppose you do need av_parser_*. Personally I'm not familiar with av_parser_* which is pretty low level.

I created the parse2 function

I took a very brief look, you're making a big breaking change to codec::Context by adding pub fields, which is unacceptable. I think if the av_parser_* API should be implemented, it should be separate from the decoder API, but this has to be thought through, and to be clear I haven't familiarized myself with the API and don't have the capacity to do so in the near future. (As stated in README: the crate is in maintenance-only mode for the most part, and I don't have much time to implement new features or even review PRs implementing them.) I can leave this open until I have time or manage to find a collaborator.

I'm also adding support for compilating against ffmpeg with vdpau, which also have some modificaitons on the rust-ffmpeg-sys repo, I'll post later.

That sort of change is easy to review, so by all means open a PR when you're ready.

lattice0 commented 3 years ago

@zmwangx I agree with you, it's not good like this. But I tried creating the parser separatedly:

https://github.com/lucaszanella/rust-ffmpeg-1/blob/25fb006cc6caa5d35131009d3f7ba44ec9bb68f1/src/codec/parser/context.rs#L28

https://github.com/lucaszanella/rust-ffmpeg-1/blob/25fb006cc6caa5d35131009d3f7ba44ec9bb68f1/src/codec/parser/parser.rs

When I realized I'd need to keep, inside parser, a RefCell to Context as CodecContext: av_codec_context: RefCell<CodecContext>, I realized it was not possible to do like this because Context which holds a pointer to AvCodecContext 'moves itself' to Decoder which 'moves itself' to Opened, so there cannot be a reference to its original form Context. That's why I moved parser to decoder.

I also created, in Context:

    pub packet: Packet,
    pub avcodec_parser_context: Option<*mut AVCodecParserContext>,

because otherwise Opened wouldn't be able to access them. Although I think this can be mitigated by creating functions that return them.

The reason I'm using the parser is that it didn't work for me by simply using Packet::copy. It gave me those errors:

[h264 @ 0x587c784f6640] Frame num change from 11 to 12
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] Frame num change from 12 to 13
[h264 @ 0x587c784f6640] decode_slice_header error
[h264 @ 0x587c784f6640] Frame num change from 12 to 13

I tried simply Packet::copy(bitstream_chunk) as you said, where I've opened a raw .h264 and read chunks of arbitrary size from it. On C++ in software decoding mode this method works, but I don't know if it should, because all the examples use the parser. I actually don't copy the chunk to an AvPacket in C++, I simply make the data pointer of the AvPacket point to the chunk data and the size to the size of the chunk.

On hardware decoding mode in C++ I'm sure decoding without parsing won't work, as I've tried many many times, so that's another reason for having the parser implemented: so it works with hardware decoding (which I'm adding support, as linking with vdpau is already working).

That's why I asked if anyone has success decoding h264 chunks... Couldn't make it work here.