-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
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
Encoding options #1296
Closed
+211
−20
Closed
Encoding options #1296
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
8f9205e
Adding codec_profile to scrcpy client default options.
88a00ab
Adding codecProfile to server options
15c0d5e
Adding codecProfile and setCodecProfile to the ScreenEncoder
fd5489d
Fix the printed versions (were opposite)
bc70f56
Added help and parsing of the codec-profile option
eaef1c1
Adding codec-profile option to the server exec params
c265d63
Changing codec-profile -> codec-options
aa42833
Changing codec-profile -> codec-options
fb7b2ae
Added logic to choose profile level matching the streaming properties.
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
85 changes: 85 additions & 0 deletions
85
server/src/main/java/com/genymobile/scrcpy/CodecOptions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package com.genymobile.scrcpy; | ||
|
||
import android.media.MediaCodecInfo; | ||
import android.os.Build; | ||
|
||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
|
||
public class CodecOptions { | ||
|
||
public static final String PROFILE_OPTION = "profile"; | ||
public static final String LEVEL_OPTION = "level"; | ||
|
||
private static final LinkedHashMap<Integer, String> levelsTable = new LinkedHashMap<Integer, String>() { | ||
{ | ||
// Adding all possible level and their properties | ||
// 3rd property, bitrate was added but not sure if needed for now. | ||
// Source: https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel1, "485,99,64"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel1b, "485,99,128"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel11, "3000,396,192"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel12, "6000,396,384"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel13, "11880,396,768"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel2, "11880,396,2000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel21, "19800,792,4000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel22, "20250,1620,4000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel3, "40500,1620,10000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel31, "108000,3600,14000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel32, "216000,5120,20000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel4, "245760,8192,20000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel41, "245760,8192,50000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel42, "522240,8704,50000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel5, "589824,22080,135000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel51, "983040,36864,240000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel52, "2073600,36864,240000"); | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel6, "4177920,139264,240000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel61, "8355840,139264,480000"); | ||
put(MediaCodecInfo.CodecProfileLevel.AVCLevel62, "16711680,139264,800000"); | ||
} | ||
} | ||
}; | ||
|
||
private HashMap<String, String> options; | ||
|
||
CodecOptions(HashMap<String, String> options) { | ||
this.options = options; | ||
} | ||
|
||
/** | ||
* The purpose of this function is to return the lowest possible codec profile level | ||
* that supports the given width/height/bitrate of the stream | ||
* @param width of the device | ||
* @param height of the device | ||
* @param bitRate at which we stream | ||
* @return the lowest possible level that should support the given properties. | ||
*/ | ||
public static int calculateLevel(int width, int height, int bitRate) { | ||
// Calculations source: https://stackoverflow.com/questions/32100635/vlc-2-2-and-levels | ||
int macroblocks = (int)( Math.ceil(width/16.0) * Math.ceil(height/16.0) ); | ||
int macroblocks_s = macroblocks * 60; | ||
for (Map.Entry<Integer, String> entry : levelsTable.entrySet()) { | ||
String[] levelProperties = entry.getValue().split(","); | ||
int levelMacroblocks_s = Integer.parseInt(levelProperties[0]); | ||
int levelMacroblocks = Integer.parseInt(levelProperties[1]); | ||
if(macroblocks_s > levelMacroblocks_s) continue; | ||
if(macroblocks > levelMacroblocks) continue; | ||
Ln.i("Level selected based on screen size calculation: " + entry.getKey()); | ||
return entry.getKey(); | ||
} | ||
return 0; | ||
} | ||
|
||
public Object parseValue(String profileOption) { | ||
String value = options.get(profileOption); | ||
switch (profileOption) { | ||
case PROFILE_OPTION: | ||
case LEVEL_OPTION: | ||
return NumberUtils.tryParseInt(value); | ||
default: | ||
return null; | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
server/src/main/java/com/genymobile/scrcpy/NumberUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.genymobile.scrcpy; | ||
|
||
public class NumberUtils { | ||
|
||
public static int tryParseInt(final String str) { | ||
return tryParseInt(str, 0); | ||
} | ||
|
||
public static int tryParseInt(final String str, int defaultValue) { | ||
try { | ||
return Integer.parseInt(str); | ||
} catch (NumberFormatException e) { | ||
return defaultValue; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
(so this class would not be needed at all)
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 don't think its a smart idea to let the user pass down any key=value pair he wants...
He can totally mess up and give random values and things that might even break the encoding and he won't be aware that he was giving something wrong.
I don't know about the other options but in case of profile and level it is suggested that if you provide a profile, you will also set a level, this is why when only profile (without level) is provided by the user, there is a calculation based on the screen size that should decide the level.
My goal was not to allow the user to pass down any key=value pair he wants, but to allow you or whoever wants to, to expand on the current CodecOptions and easily add new options that he can choose how they will be parsed and what will happen with them and where in the code.
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.
It would allow to configure the codec generically, without having to build the app.
For advanced options, I would prefer a generic way.
At least, we can warn if the provided key is not supported:(EDIT: in fact, it just tells whether we set a key for the format)containsKey()
.User can already pass random values (a bitrate of 1Mbps for instance), which is "ignored" by the codec without warnings.
Isn't it done automatically if you don't provide the level? #1226 (comment)
Btw, contrary to what I said here, there is no need to specify the type in the string, it can be requested:
getValueTypeForKey
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.
OK, it will be done your way :)
Thanks for the good lesson.
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.
@rom1v
Just a quick question, what if the key is supported but value is not supported by the device?
If we are assuming the codec ignores bad values shouldn't the user know about it somehow?
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.
getValueTypeForKey is API29+ ...
What do you suggest?
We can go back to what you said, assuming int unless specified key:type=value
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.
@rom1v Ping
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 device will just ignore it I guess. Like if for now you pass
--max-fps
but the encoder does not support it.:(
Hmm, yes... I have no better solution then :(
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.
OK, so I've made the changes on our side, ill need to update my dev branch and make a new PR.
@rom1v
Just to make things clear before i make a new PR, the expected value types are
Integer/int - String/str - Float/float - Long/long
Yes?