transcoding: Use CamcorderProfile bitrate for transcoding.

Bug: 176932192
Test: Record video with GCA in 1080P@30fps and 4K@30fps and verify
the bitrate in camcorder profile is used.
Change-Id: I3dfd01c1b8531d656bae1eee54b49e2f74e7d355

Change-Id: Ibe2a18471364956da25f4585601fab5b19eb4f53
This commit is contained in:
hkuang
2021-01-06 16:42:08 -08:00
parent 397070ce13
commit 57c0f56bf7

View File

@@ -109,6 +109,9 @@ public final class MediaTranscodeManager {
/** Interval between trying to reconnect to the service. */
private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
/** Default bpp(bits-per-pixel) to use for calculating default bitrate. */
private static final float BPP = 0.25f;
/**
* Default transcoding type.
* @hide
@@ -1002,14 +1005,92 @@ public final class MediaTranscodeManager {
if (!shouldTranscode()) {
return null;
}
// TODO(hkuang): Only modified the video codec type, and use fixed bitrate for now.
// May switch to transcoding profile when it's available.
MediaFormat videoTrackFormat = new MediaFormat(mSrcVideoFormatHint);
videoTrackFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
videoTrackFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH);
int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException(
"Source Width and height must be larger than 0");
}
// TODO(hkuang): Remove the hardcoded frameRate after b/176940364 is fixed.
float frameRate = (float) 30.0;
/*mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE, frameRate);
if (frameRate <= 0) {
throw new IllegalArgumentException(
"frameRate must be larger than 0");
}*/
int bitrate = getAVCBitrate(width, height, frameRate);
videoTrackFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
return videoTrackFormat;
}
/**
* Generate a default bitrate with the fixed bpp(bits-per-pixel) 0.25.
* This maps to:
* 1080P@30fps -> 16Mbps
* 1080P@60fps-> 32Mbps
* 4K@30fps -> 62Mbps
*/
private static int getDefaultBitrate(int width, int height, float frameRate) {
return (int) (width * height * frameRate * BPP);
}
/**
* Query the bitrate from CamcorderProfile. If there are two profiles that match the
* width/height/framerate, we will use the higher one to get better quality.
* Return default bitrate if could not find any match profile.
*/
private static int getAVCBitrate(int width, int height, float frameRate) {
int bitrate = -1;
int[] cameraIds = {0, 1};
// Profiles ordered in decreasing order of preference.
int[] preferQualities = {
CamcorderProfile.QUALITY_2160P,
CamcorderProfile.QUALITY_1080P,
CamcorderProfile.QUALITY_720P,
CamcorderProfile.QUALITY_480P,
CamcorderProfile.QUALITY_LOW,
};
for (int cameraId : cameraIds) {
for (int quality : preferQualities) {
// Check if camera id has profile for the quality level.
if (!CamcorderProfile.hasProfile(cameraId, quality)) {
continue;
}
CamcorderProfile profile = CamcorderProfile.get(cameraId, quality);
// Check the width/height/framerate/codec, also consider portrait case.
if (((width == profile.videoFrameWidth
&& height == profile.videoFrameHeight)
|| (height == profile.videoFrameWidth
&& width == profile.videoFrameHeight))
&& (int) frameRate == profile.videoFrameRate
&& profile.videoCodec == MediaRecorder.VideoEncoder.H264) {
if (bitrate < profile.videoBitRate) {
bitrate = profile.videoBitRate;
}
break;
}
}
}
if (bitrate == -1) {
Log.w(TAG, "Failed to find CamcorderProfile for w: " + width + "h: " + height
+ " fps: "
+ frameRate);
bitrate = getDefaultBitrate(width, height, frameRate);
}
Log.d(TAG, "Using bitrate " + bitrate + " for " + width + " " + height + " "
+ frameRate);
return bitrate;
}
/**
* Retrieves the audio track format to be used for transcoding.
*