-
Notifications
You must be signed in to change notification settings - Fork 440
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
Fix timestamps across concatenated TSes #906
base: main
Are you sure you want to change the base?
Conversation
Hi @rohitjoins, is there any additional info I can provide to help you reviewing this PR? |
Hi @dsparano, I haven't got time yet to look at this yet. Will review this soon and let you know. Thank you for the patience. |
Hi - would it be possible to open a new PR from an individual-owned fork? We can't push changes to organization-owned forks like this one unless we have collaborator access. If that's not possible then we can still merge this PR but it will result in an 'evil' merge. See more info here: https://github.com/androidx/media/blob/release/CONTRIBUTING.md#push-access-to-pr-branches |
@rohitjoins I've given you write access on our forked repo, please let me know if you cannot write. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the TsExtractorTest
tests are failing after this change. The duration for the sample files in the dump files shows quite an increase. Can you also look into that?
* end. This class can only be used once to read duration from a given stream, and the usage of the | ||
* <p>This reader extracts the duration by reading DTS values of the first PES PID packets at the | ||
* start and at the end of the stream, calculating the difference, and converting that into stream | ||
* duration. Should DTS not be available this reader falls back to using PCR in the same way and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
back to using PCR in the same way
I think you should leave the explanation from before about how it is done. Same way
will not be known to reader of this documentation in the future unless you're seeing the diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the description, although this is now a private method
firstDtsValue = C.TIME_UNSET; | ||
secondDtsValue = C.TIME_UNSET; | ||
lastDtsValue = C.TIME_UNSET; | ||
firstDtsPosition = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Use C.POSITION_UNSET
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed, however C.POSITION_UNSET is deprecated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for suggesting a deprecated constant. Please use C.INDEX_UNSET
as documented on the deprecated constant C.POSITION_UNSET
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No prob, changed
return finishReadDuration(input); | ||
} | ||
|
||
public @Extractor.ReadResult int computeDuration( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add documentation to this new method as done for readDuration
as this is a public method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed as per below comment
return finishReadDuration(input); | ||
} | ||
|
||
public @Extractor.ReadResult int computeDuration( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name computeDuration
makes little sense when we already have another called readDuration
. Use a better name here and may be also change the method name for readDuration
to something like readDurationFromPcr
and readDurationFromDts
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, makes sense. So I've changed the two methods as readDurationFromPcr
and readDurationFromDts
, however having added the fallback these two can now be private and the readDuration
is now the public one handling the fallback.
return durationReader.readDuration(input, seekPosition, pcrPid); | ||
int pesPid = getFirstPesReaderPid(); | ||
if (canReadDuration && !durationReader.isDurationReadFinished() && pesPid > 0) { | ||
return durationReader.computeDuration(input, seekPosition, pesPid); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the fallback logic to use readDuration
as before when DTS data is not available? Also why is it more accurate to use DTS data to calculate the duration rather than the PCR apart from the use case mentioned in the issue description?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added the fallback in readDuration
. The problem with the PCR is what I mentioned in the PR description, will elaborate more in there.
Repeating again, please check the failing test cases in |
Re the TsDurationReaderTest. I've checked the test TS
However:
To complicate things the DTS and PTS values are a bit strange:
(Note: the last encoded frame has the highest PTS so it it the last also in presentation order) The PTS/DTS are on a 90KHz tick so given that the stream is 24fps this gives a 90000/24 = 3750 ticks/frame. What happens with this encode is that the last-first DTS diff is 354750-126000 = 228750 ticks equal to 61 frames, plus the last (or first depending how you see it) this gives 62 frames, which seems wrong. Also, this PR assumes equally spaced DTS (which seems a fair assumption) while the diff second-first DTS here is 137250-126000 = 11250 which is 3 frames duration. Long story short I'm not entirely sure this is a fully conformant stream, or one meaningful to be used for testing. |
On the other hand if we take the test file
Timestamps:
Therefore: Duration based on DTS: 87000 + 3000 = 90000 which is 1 sec, which is correct. |
Not sure how the original bbb_2500ms.ts was encoded, anyway I just did:
and the resulting asset is totally equivalent with the current one, but with correct frame count and timestamps, so I've added it to this PR. I've also added I'm currently looking at the tests, many dumps need updating because of the different durations we now get. There are a few failings I'm currently analysing. |
Will this fix reduce the chance of "Unexpected audio track timestamp discontinuity" being thrown? |
@FongMi I'm struggling to find a device supporting audio mpeg-L2, any suggestion? |
|
@FongMi could play your content on a Samsung S21, the |
bfb73f4
to
5096fba
Compare
@rohitjoins I've done a few updates and refreshed many dump files. Tests are all passing now, if you could please check the changes. |
Hi @dsparano, Thank you for addressing the comments. Please be patient as this is a big change. Will get this reviewed internally if I don't find anything to flag before that. Note: I'm going on vacation for 3 weeks soon, so expect a delay. |
Hi @rohitjoins have you had the chance to make progress with this review? |
… timestamp search window due to second DTS search
…500ms.ts; fix line-feed test errors on Windows
…nd add dumps; add .gitattributes
Hi @rohitjoins I've rebased and updated a few dump files, can you please resume your review? |
Hi @dsparano, I'll take a look again on this PR and will let you know if there are any further concerns to merge this. |
Hi @rohitjoins have you had the chance to review this? Can I help in any way? |
Problem
When a playlist of TS assets is played, at the point of stream change the following TS may have one or more frame timestamps repeated. See this example with the last 5 frames of the previous TS and the first 5 frames of the next one.
Current main:
Correct sequence should be:
Time stamps us 1000004000000 and 1000004040000 get repeated. This has an impact in applications where timestamp accuracy is required.
Root cause
From our analysis the root cause seems to be the calculated asset duration. The duration of a Transport Stream asset gets calculated as difference between the very last PCR and the very first PCR encountered in the stream. However this seems to bring some issues:
Proposed solution
As a mitigation we propose here a change to use DTS, in pretty much the same way. Since the DTS is monotonic it allows to easily calculate both the frame duration (point 2) and the asset duration. Specifically: frame duration as difference between two consecutive DTSes (2nd and 1st) and asset duration as difference between last DTS and first DTS, and corrected by adding one frame duration.
In the unlikely event the DTS is not available, this PR would still fall back to using the PCR as in current main.