-
Notifications
You must be signed in to change notification settings - Fork 115
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
AV1 samplebuilder support (WIP) #264
base: master
Are you sure you want to change the base?
Conversation
I was not able to test further as IsPartitionHead always false |
This adds IsPartitionHead and IsPartitionTail to AV1Packet.
AV1 RTP payload cannot be concatenated without first recovering the omitted OBU length.
Fixed. However, as I've mentioned, this is completely untested, and I'd be very surprised if it worked. The question is whether you agree that this could work in principle, since it is both more efficient and simpler than what you propose. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #264 +/- ##
==========================================
- Coverage 86.21% 84.70% -1.52%
==========================================
Files 22 22
Lines 1734 1765 +31
==========================================
Hits 1495 1495
- Misses 203 234 +31
Partials 36 36
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
AppendToSample implementation is wrong. There are maybe several OBUS in AV1Packet and AppendToSample should run the similar loop as func (p *AV1Packet) Unmarshal But there is much simplier approach much better than my and yours: just return OBULen+OBU list right from Unmarshal All my fix was to workaround current useless av1 format. your AppendToSample introduce to keep current format but to produce right format after Unmarshal. Shouldn't we just return all we need from Unmarshal. Yes, we need to allocate for sample but your implementation do the same, but for only one OBU. This is wrong. There maybe multiple OBUs in Av1Packet. |
Interesting.
That's right, and my implementation builds a sample as a sequence of LE128-prefixed OBUs. Are you suggesting a different representation?
https://github.com/jech/galene/blob/master/codecs/codecs.go#L48 This code does the equivalent of AV1Packer.Unmarshal in an efficient manner. I had to write it because Unmarshal was written by people who don't care about efficiency.
Unmarshal is a low-leve function that should run in constant time and perform no allocations. Check the H264 version of Unmarshal, it's done right, it doesn't try to parse the list of NALUs. Please also read the comments in #265 and #266. |
@alexpokotilo Another point is that you cannot reassemble fragmented OBUs in |
@jech, maybe my problem is that I see AppendToSample implementation but don't see its usage in your branch. Could you please finish your version so I can just use it and check it really support all cases. Long story short. You are right and my version is not ideal. I don't like it either. From performance pov it doesn't matter where you process OBUs: in unmarshal method or in AppendToSample right next to it. Now AV1Packet just drop OBUElements on every unmarshal. it doesn't care about previous fragments. I had to use AV1Frame to combine OBUs from AV1Packets as AV1Packet doesn't care about it. What you propose is :
Don't get me wrong please. I admit my initial approach is wrong and I'm starving to test your version but it doesn't exist. I still don't see a problem in adding tail support into AV1Packets the same way H264Packet do and return necessary format from it without adding new interface AppendToSample. at the end of the day you will have to allocate somewhere. Why not in unmarshal ? What so special in this method so that you don't want to do the job there? these Packet structures are used mainly in samplebuilder. You don't add any gain moving processing in new method AppendToSample. If you complain about unmarshal-only approach only from design POV - I'm sorry I don't completely confident to speak from design POV. I'm not Packet approach designer. But If you think your approach gain something to samplebuffer users - please complete it and I will create performance test to check where you are right or not. I think it's time to complete AppendToSample so I can do tests and check whether it works or not. Now I cannot and don't see how I can help to prove your points or argue with them. My main problem with AppendToSample approach is that I don't get what is so special with av1 so we need to handle it different way from h264? do we have tails in h264? yes, we do. How we process them? in unmarshal. Do we do allocation in h264's unmarshals? Yes, in case we have previous tail. Does h264' unmarshal return ready to append buffer? Yes, it is. You want to have lightweight header parser without all body processing - go ahead but this is a different story. Do I agree that AV1Packet made in different way than others Packets? Yes. This is all I can say about it. |
Please look at H264Packet. it does process tails from previous unmarshal call relying on the fact that samplebuffer call unmarshal in correct order. This is what I see in the code at least. Check func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) and it's p.fuaBuffer processing. If unmarshal didn't rely on packet order this approach would not work for h264. |
Yes, and that's wrong, for at least three reasons:
Alex, let us please do the right thing in AV1, and let's fix H.264. I've started here:
Because Unmarshal is not optional: if you want to work with a packet, you must call Unmarshal. Any other methods are optional, you only call them if you need the functionality. Pion is designed to be suitable for many different applications, from full-featured multimedia applications (that do encoding, decoding and so on) to fast media servers (that want to push massive amounts of packets around while paying as little overhead as possible. We must endeavour to make sure that Pion remains widely usable, and doesn't become optimised for one specific class of applications. |
So maybe add Another method to help these application and keep current interface to others ? |
@jech any plans to continue on this one? If not can you please sum up what needs to be done? maybe somebody take over |
Yes, I'm planning to work on it. I'm actually planning a fairly comprehensive rework of the packet code:
Unfortunately, I won't be able to work on that before the end of October. |
Sounds exciting, please let me know if you would need help with testing. Does this PR is going to solve #273 ? |
Hello, I'm going to start working on AV1 support next, can I adopt this? :) |
No, but we can work together. |
I meant asking if I can continue your work; I have time to work on it, and I do agree with your approach here :) can you share with me with me what you found with this experiential and the rest of your vision? fixing other codecs seems interesting but we must do it in a breaking way. |
Currently, the samplebuilder does that:
At first sight, that looks good, but in practice the Depacketizer interface is implemented by the various packet types, which is wrong, since it confuses, say, XXXPacket.Unmarshal and Depacketizer.Unmarshal. But from the point of the library user the two functions have different usage patterns:
An example of the confusion is here: https://github.com/pion/rtp/blob/master/codecs/h264_packet.go#L186. The H264Packet contains state (fuaBuffer) which the Unmarshal method uses to carry dependencies between packets. The effect is that if the H264packet.Unmarshal method is called non-sequentially (say, in reception order rather than in seqno order), the data will become corrupted. We'll hit the same issue with AV1. (VP8 and VP9 have simple packetisation rules that don't require state.) The solution is to add a method Finally, as long as we're breaking compatibility, we should replace the Depacketizer.Unmarshal function with
which does the equivalent of
This way, the SampleBuilder can call AppendData instead of Unmarshal, avoiding one allocation. |
As a user of the library this confused me with the h264 library.
I don't think we can break it now, maybe we add a new interface and make it work with the new interface and the old Unmarshal / Marshal. This way we can add to What do you think? |
I think we should first implement the right thing on a separate branch, without regard to backwards compatibility. Once we're agreed that's the right thing, we see how much nasty hacks we can accept in order to preserve compatibility. |
I'm down for this and I have the time and the energy to do both, but first I think I will have to ship it to this repo, I think your approach is good, and we can do type check. But do you mean i should ship it with marshal / unmarshal, And we make the new |
I think that for now we can work with the current The AppendData optimisation we can do at a later stage. |
maybe we can just update the Depacketizer interface to this and leave the edit: Never mind i realized this will break user provided type Depacketizer interface {
// soft deprecated, just for end users.
Unmarshal(packet []byte) ([]byte, error)
// what pion will use.
AppendData(dest *[]byte, packet []byte) error
IsPartitionHead(payload []byte) bool
IsPartitionTail(marker bool, payload []byte) bool
} what do you think @jech ? |
Okay i see, so do i make a PR for Unmarshal for |
I think we definitely should not continue with the broken approach. I would start with adding the following method to all of the XXXPacket types:
Then either modify all of the examples that use the samplebuilder to probe the packet for the GetDepacketizer method, or else modify the SampleBuilder itself to call GetDepacketizer before starting depacketisation. Not sure which is the right approach. Once that is done, we can start adding non-broken depacketizers to all of the XXXPacket types. |
The only reason is that I don't want to break anything for the end user :) and I want the current users to be able to use Maybe the two interfaces approach is good? I want to ship av1 and fix all the reported bugs related to av1 by this week. If you found a good way to do all of this without breaking any changes, just provide your design approach and i will ship the implementation in no time :) |
Sorry, I edited my prvious message just after you replied. |
Okay I think this is good, the only issue if users provide their own |
The point I'm making is that while we should strive not to break compatibility for existing codecs, we should not implement the broken approach for AV1: if we add a new non-broken API, then we should leverage AV1 to encourage people to switch to the new API. |
Okay, So I'm not really sure, I think your approach is obviously better for What do you think? |
In my experience, getting others to agree is easier when you have working code to show them. |
Well, my point is that I don't want to waste time that can be spent on other issues :) but let's say we can break changes what do you think the final design should look like? |
sb := depacketizer.New(... codecs.AV1Packet{}.GetDepacketizer(), ...)
var p AV1Packet
for {
n, err := track.Read(buf)
p.Unmarshal(buf, n)
depacketizer.Push(&p)
for {
...
depacketizer.PopWithTimestamp()
..
} The only change wrt. what is done now is the call to So short term plan:
In order to make GetDepacketizer compulsory for AV1, you simply don't implement the PartitionHead methods on AV1Packet, only on AV1Depacketizer. Medium term plan:
Long term plan:
|
I think it's a good idea to send a pointer to this discussion to Slack. I'll try to check if there's any discussion on Slack, but no promises, I'm developing Slack-phobia. What's wrong with mailing lists? Grumble, unsearchable proprietary crap, grumble, no proper archive, grumble, and now get off my loan ;-) |
Okay i posted it to the slack, we will see by tomorrow, I'm going to work on other issues today :) |
An attempt to implement the required hooks for the samplebuilder
to work with AV1. This approach is likely to be both faster and
simpler than the one in #238.
COMPLETELY UNTESTED, DO NOT COMMIT.