-
Notifications
You must be signed in to change notification settings - Fork 6k
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
Add AC-4 DRM Support #6797
Add AC-4 DRM Support #6797
Conversation
ybai001
commented
Dec 23, 2019
- AC-4 DRM MPEG-DASH On-Demand Profile
- AC-4 DRM MPEG-DASH Live Profile
- AC-4 DRM HLSv7 (fmp4) On-Demand Profile
- AC-4 DRM HLSv7 (fmp4) Live Profile
Merge pull request #3 from google/dev-v2
Merge from google/ExoPlayer/dev-v2
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. ℹ️ Googlers: Go here for more info. |
@andrewlewis This license issue is same as pull request #5438. (Due to two contributors on same branch.) Could you help to manually verified that the CLAs? Thanks. |
|
CLA verified manually. (Committers are ybai and aujohn on corporate CLA.) |
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
@AquilesCanta Could you take a look at this change? |
I can take an initial look at this, to get the ball rolling. |
I put a fairly substantial comment in-line, so please take a look at that. If you agree, I'd suggest first sending a pull request that just moves writing the AC4 header to its new location, both in |
@@ -1269,6 +1270,7 @@ private boolean readSample(ExtractorInput input) throws IOException, Interrupted | |||
} | |||
sampleBytesWritten = currentTrackBundle.outputSampleEncryptionData(); | |||
sampleSize += sampleBytesWritten; | |||
outputSampleEncryptionDataSize = sampleBytesWritten; | |||
parserState = STATE_READING_SAMPLE_CONTINUE; | |||
sampleCurrentNalBytesRemaining = 0; | |||
isAc4HeaderRequired = |
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'm not sure if I'm missing something, but is there a reason not to output the AC4 header directly here, removing the need for isAc4HeaderRequired
and outputSampleEncryptionDataSize
? The same is true for Mp4Extractor
as well, so if you end up doing this, please do it there as well.
I also think you should avoid changing SampleQueue
and SampleDataQueue
as part of this change. In the current proposal, the sample data is modified in the extractor (by adding the header) but the associated encryption data is not. This means there's a mismatch between the sample data and associated encryption data in the sample queue, which seems wrong to me. The encryption data is then fixed on the reading side of the sample queue. Instead of doing it this way, I think the encryption data should really be fixed on the writing side of the sample queue in the extractor, since that's where the sample data is modified.
If both of these points make sense, I think you can do something like this (replacing the code here, starting from where you need to call outputSampleEncryptionData
):
boolean isAc4HeaderRequired =
MimeTypes.AUDIO_AC4.equals(currentTrackBundle.track.format.sampleMimeType);
int encryptionDataBytesWritten = currentTrackBundle.outputSampleEncryptionData(
sampleSize, isAc4HeaderRequired ? Ac4Util.SAMPLE_HEADER_SIZE : 0);
sampleBytesWritten = encryptionDataBytesWritten;
sampleSize += encryptionDataBytesWritten;
if (isAc4HeaderRequired) {
Ac4Util.getAc4SampleHeader(sampleSize, scratch);
currentTrackBundle.output.sampleData(scratch, Ac4Util.SAMPLE_HEADER_SIZE);
sampleBytesWritten += Ac4Util.SAMPLE_HEADER_SIZE;
sampleSize += Ac4Util.SAMPLE_HEADER_SIZE;
}
parserState = STATE_READING_SAMPLE_CONTINUE;
sampleCurrentNalBytesRemaining = 0;
Where TrackBundle.outputSampleEncryptionData
corrects the encryption data as it writes it into the sample queue. That will be a bit tricky to get right, but roughly speaking, the bottom half of that method needs to look more like this (with the // TODO
bits done):
/**
* Outputs the encryption data for the current sample.
*
* @param sampleSize The size of the current sample in bytes, excluding any additional clear
* header that will be prefixed to the sample by the extractor.
* @param clearHeaderSize The size of a clear header that will be prefixed to the sample by the
* extractor, or 0.
* @return The number of written bytes.
*/
public int outputSampleEncryptionData(int sampleSize, int clearHeaderSize) {
// .... top half of the method as it is currently. Then:
boolean haveSubsampleEncryptionTable =
fragment.sampleHasSubsampleEncryptionTable(currentSampleIndex);
boolean writeSubsampleEncryptionData =
haveSubsampleEncryptionTable | clearHeaderSize != 0;
// Write the signal byte, containing the vector size and the subsample encryption flag.
encryptionSignalByte.data[0] =
(byte) (vectorSize | (writeSubsampleEncryptionData ? 0x80 : 0));
encryptionSignalByte.setPosition(0);
output.sampleData(encryptionSignalByte, 1);
// Write the vector.
output.sampleData(initializationVectorData, vectorSize);
if (!writeSubsampleEncryptionData) {
return 1 + vectorSize;
}
if (!haveSubsampleEncryptionTable) {
// TODO: Need to synthesize subsample encryption data. The sample is fully encrypted except
// for the additional header that the extractor is going to prefix, so we need to write the
// following to output.sampleData:
// subsampleCount (unsigned short) = 1
// clearDataSizes[0] (unsigned short) = clearHeaderSize
// encryptedDataSizes[0] (unsigned int) = sampleSize
return 1 + vectorSize + 8;
}
ParsableByteArray subsampleEncryptionData = fragment.sampleEncryptionData;
int subsampleCount = subsampleEncryptionData.readUnsignedShort();
subsampleEncryptionData.skipBytes(-2);
int subsampleDataLength = 2 + 6 * subsampleCount;
// TODO: On the way through, we need to re-write the 3rd and 4th bytes, which hold
// clearDataSizes[0], so that clearHeaderSize is added into the value. This must be done
// without modifying subsampleEncryptionData itself.
output.sampleData(subsampleEncryptionData, subsampleDataLength);
return 1 + vectorSize + subsampleDataLength;
}
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.
Note: I edited this to correct some mistakes, so please look on GitHub rather than relying on the email :).
clearDataSizes[0] = 0; | ||
encryptedDataSizes[0] = extrasHolder.size - (int) (offset - extrasHolder.offset); | ||
int addedHeaderSize = MimeTypes.AUDIO_AC4.equals(mimeType) ? 7 : 0; | ||
clearDataSizes[0] = addedHeaderSize; |
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.
See comment elsewhere about not modifying this class at all, however as an aside I don't think you should be assuming there's no sub-sample encryption (i.e. you'd also need to do something in the if
block above, as well as the else
block here).
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.
@ojw28 The fact is I added code in if
block but I removed it when I submitted this pull request. The reason is there is no this kind of stream inside Dolby so that I can't test that if
branch. I can double check with our content creation team whether they will create this kind of stream in future. BTW, according to your experience, is there sub-sample encryption content for audio track (e.g. aac) in practice? Thanks.
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'm not sure whether sub-sample encryption is really a thing for audio samples, but I think we should handle the possibility :).
We're still treating this as low priority, as per #6488. It's also only becoming less important over time, due to the shift to CMAF. I don't really see much value in adding support at this point. |
OK, I got your point. |
OK. I'll submit a new pull request to move writing the AC4 header to its new location and add test assets at the same time. Then I'll update AC-4 DRM pull request. |
Hi, @ojw28, BR, |
Regarding the CLA issue:
Since we don't have your GitHub usernames registered, we don't recognize the commits as being from you unless you use your work email addresses. Hence the problem :). There are a few things you can try to fix this:
I suspect the first approach would be more robust because it doesn't rely on your configuring Git properly on all your devices. |
The first of your pull requests has been merged (with some modifications to fix the issues highlighted by the tests). Let me know once this one is updated. Thanks for your help! |
Update cleardatasize[0] in extractor rather than sampleDataQueue.
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. ℹ️ Googlers: Go here for more info. |
Done. Updated code based on your comments. Please help to review it. Your method is better than my original one. Thank you very much for your detailed instruction and example code. |
...y/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
Show resolved
Hide resolved
...y/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
Show resolved
Hide resolved
...y/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java
Show resolved
Hide resolved
Thanks for your warmhearted. I'll try to solve this issue. (Sorry, seem that you need to approve it again since I updated this pull request.) |
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |
Is it possible for you to add another test case ( It's fine to cover just the full-sample-encryption case, given you're not generating audio streams that use sub-sample encryption at the moment (and, therefore, I assume it's non-trivial for you to add such a corresponding test case :)). |
We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors. If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA (login here to double check)? If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google. ℹ️ Googlers: Go here for more info. |
Done. And I need to solve CLA issue ASAP. Otherwise, you need to manually approve it again and again. Sorry for that. |
A Googler has manually verified that the CLAs look good. (Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.) ℹ️ Googlers: Go here for more info. |