mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 03:23:07 +00:00
Merge branch 'v2.5'
Conflicts: libs/limelight-common.jar
This commit is contained in:
commit
cc37da9a56
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.limelight"
|
package="com.limelight"
|
||||||
android:versionCode="18"
|
android:versionCode="19"
|
||||||
android:versionName="2.4" >
|
android:versionName="2.5 (alpha)" >
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="16"
|
android:minSdkVersion="16"
|
||||||
|
10
decoder-errata.txt
Normal file
10
decoder-errata.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
This file serves to document some of the decoder errata when using MediaCodec hardware decoders on certain devices.
|
||||||
|
|
||||||
|
1. num_ref_frames is set to 16 by NVENC which causes decoders to allocate 16+ buffers. This can cause an OOM error on some devices.
|
||||||
|
- Affected decoders: TI OMAP4, possibly some Qualcomm chips too (Galaxy S3 on 4.3+)
|
||||||
|
|
||||||
|
2. Some decoders have a huge per-frame latency with the unmodified SPS sent from NVENC. Setting max_dec_frame_buffering fixes this latency issue.
|
||||||
|
- Affected decoders: NVIDIA Tegra 3 and 4
|
||||||
|
|
||||||
|
3. Some decoders strictly require that you pass BUFFER_FLAG_CODEC_CONFIG and crash upon the IDR frame if you don't
|
||||||
|
- Affected decoders: TI OMAP4
|
@ -37,21 +37,22 @@ or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>na
|
|||||||
public static final int ouya_icon=0x7f020002;
|
public static final int ouya_icon=0x7f020002;
|
||||||
}
|
}
|
||||||
public static final class id {
|
public static final class id {
|
||||||
public static final int autoDec=0x7f080006;
|
public static final int autoDec=0x7f080004;
|
||||||
public static final int bitrateLabel=0x7f08000c;
|
public static final int bitrateLabel=0x7f08000b;
|
||||||
public static final int bitrateSeekBar=0x7f08000d;
|
public static final int bitrateSeekBar=0x7f08000c;
|
||||||
public static final int config1080p30Selected=0x7f08000a;
|
public static final int config1080p30Selected=0x7f080009;
|
||||||
public static final int config1080p60Selected=0x7f08000b;
|
public static final int config1080p60Selected=0x7f08000a;
|
||||||
public static final int config720p30Selected=0x7f080008;
|
public static final int config720p30Selected=0x7f080007;
|
||||||
public static final int config720p60Selected=0x7f080009;
|
public static final int config720p60Selected=0x7f080008;
|
||||||
public static final int decoderConfigGroup=0x7f080003;
|
public static final int decoderConfigGroup=0x7f080001;
|
||||||
public static final int hardwareDec=0x7f080007;
|
public static final int hardwareDec=0x7f080005;
|
||||||
public static final int hostTextView=0x7f080000;
|
public static final int hostTextView=0x7f080000;
|
||||||
public static final int pairButton=0x7f080002;
|
public static final int pairButton=0x7f080006;
|
||||||
public static final int softwareDec=0x7f080005;
|
public static final int quitButton=0x7f08000e;
|
||||||
public static final int statusButton=0x7f080001;
|
public static final int softwareDec=0x7f080003;
|
||||||
public static final int streamConfigGroup=0x7f080004;
|
public static final int statusButton=0x7f08000d;
|
||||||
public static final int surfaceView=0x7f08000e;
|
public static final int streamConfigGroup=0x7f080002;
|
||||||
|
public static final int surfaceView=0x7f08000f;
|
||||||
}
|
}
|
||||||
public static final class layout {
|
public static final class layout {
|
||||||
public static final int activity_connection=0x7f030000;
|
public static final int activity_connection=0x7f030000;
|
||||||
|
Binary file not shown.
@ -24,26 +24,6 @@
|
|||||||
android:inputType="textNoSuggestions"
|
android:inputType="textNoSuggestions"
|
||||||
android:hint="IP address of GeForce PC" />
|
android:hint="IP address of GeForce PC" />
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/statusButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@+id/hostTextView"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:text="Start Streaming Steam!" >
|
|
||||||
|
|
||||||
<requestFocus />
|
|
||||||
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/pairButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@+id/statusButton"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:text="Pair with PC" />
|
|
||||||
|
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
android:id="@+id/decoderConfigGroup"
|
android:id="@+id/decoderConfigGroup"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
@ -128,6 +108,35 @@
|
|||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_below="@+id/decoderConfigGroup"
|
android:layout_below="@+id/decoderConfigGroup"
|
||||||
android:layout_toLeftOf="@+id/bitrateLabel" />
|
android:layout_toLeftOf="@+id/bitrateLabel" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/pairButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignRight="@+id/statusButton"
|
||||||
|
android:layout_below="@+id/statusButton"
|
||||||
|
android:layout_marginRight="114dp"
|
||||||
|
android:text="Pair with PC" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/statusButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/hostTextView"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:text="Start Streaming Steam!" >
|
||||||
|
|
||||||
|
<requestFocus />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/quitButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_above="@+id/streamConfigGroup"
|
||||||
|
android:layout_alignLeft="@+id/statusButton"
|
||||||
|
android:layout_marginLeft="122dp"
|
||||||
|
android:text="Quit Steam" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ import android.content.Intent;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
public class Connection extends Activity {
|
public class Connection extends Activity {
|
||||||
private Button statusButton, pairButton;
|
private Button statusButton, pairButton, quitButton;
|
||||||
private TextView hostText;
|
private TextView hostText;
|
||||||
private SharedPreferences prefs;
|
private SharedPreferences prefs;
|
||||||
private RadioButton rbutton720p30, rbutton720p60, rbutton1080p30, rbutton1080p60;
|
private RadioButton rbutton720p30, rbutton720p60, rbutton1080p30, rbutton1080p60;
|
||||||
@ -69,6 +69,7 @@ public class Connection extends Activity {
|
|||||||
|
|
||||||
this.statusButton = (Button) findViewById(R.id.statusButton);
|
this.statusButton = (Button) findViewById(R.id.statusButton);
|
||||||
this.pairButton = (Button) findViewById(R.id.pairButton);
|
this.pairButton = (Button) findViewById(R.id.pairButton);
|
||||||
|
this.quitButton = (Button) findViewById(R.id.quitButton);
|
||||||
this.hostText = (TextView) findViewById(R.id.hostTextView);
|
this.hostText = (TextView) findViewById(R.id.hostTextView);
|
||||||
this.rbutton720p30 = (RadioButton) findViewById(R.id.config720p30Selected);
|
this.rbutton720p30 = (RadioButton) findViewById(R.id.config720p30Selected);
|
||||||
this.rbutton720p60 = (RadioButton) findViewById(R.id.config720p60Selected);
|
this.rbutton720p60 = (RadioButton) findViewById(R.id.config720p60Selected);
|
||||||
@ -244,6 +245,73 @@ public class Connection extends Activity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.quitButton.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (Connection.this.hostText.getText().length() == 0) {
|
||||||
|
Toast.makeText(Connection.this, "Please enter the target PC's IP address in the text box at the top of the screen.", Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toast.makeText(Connection.this, "Trying to quit Steam...", Toast.LENGTH_SHORT).show();
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String macAddress;
|
||||||
|
try {
|
||||||
|
macAddress = NvConnection.getMacAddressString();
|
||||||
|
} catch (SocketException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macAddress == null) {
|
||||||
|
LimeLog.severe("Couldn't find a MAC address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvHTTP httpConn;
|
||||||
|
String message;
|
||||||
|
try {
|
||||||
|
httpConn = new NvHTTP(InetAddress.getByName(hostText.getText().toString()),
|
||||||
|
macAddress, PlatformBinding.getDeviceName(), PlatformBinding.getCryptoProvider(Connection.this));
|
||||||
|
if (httpConn.getPairState() == PairingManager.PairState.PAIRED) {
|
||||||
|
if (httpConn.getCurrentGame() != 0) {
|
||||||
|
if (httpConn.quitApp()) {
|
||||||
|
message = "Successfully closed Steam";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message = "Failed to close Steam";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message = "Steam is not running";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
message = "Device not paired with computer";
|
||||||
|
}
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
message = "Failed to resolve host";
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
message = "GFE returned an HTTP 404 error. Make sure your PC is running a supported GPU. Using remote desktop software can also cause this error. "
|
||||||
|
+ "Try rebooting your machine or reinstalling GFE.";
|
||||||
|
} catch (Exception e) {
|
||||||
|
message = e.getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String toastMessage = message;
|
||||||
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(Connection.this, toastMessage, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.pairButton.setOnClickListener(new OnClickListener() {
|
this.pairButton.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View arg0) {
|
public void onClick(View arg0) {
|
||||||
|
@ -65,6 +65,8 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
|
|||||||
private boolean connecting = false;
|
private boolean connecting = false;
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
|
|
||||||
|
private ConfigurableDecoderRenderer decoderRenderer;
|
||||||
|
|
||||||
private WifiManager.WifiLock wifiLock;
|
private WifiManager.WifiLock wifiLock;
|
||||||
|
|
||||||
private int drFlags = 0;
|
private int drFlags = 0;
|
||||||
@ -194,6 +196,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
|
|||||||
enableLargePackets ? 1460 : 1024), PlatformBinding.getCryptoProvider(this));
|
enableLargePackets ? 1460 : 1024), PlatformBinding.getCryptoProvider(this));
|
||||||
keybTranslator = new KeyboardTranslator(conn);
|
keybTranslator = new KeyboardTranslator(conn);
|
||||||
controllerHandler = new ControllerHandler(conn);
|
controllerHandler = new ControllerHandler(conn);
|
||||||
|
decoderRenderer = new ConfigurableDecoderRenderer();
|
||||||
|
|
||||||
// The connection will be started when the surface gets created
|
// The connection will be started when the surface gets created
|
||||||
sh.addCallback(this);
|
sh.addCallback(this);
|
||||||
@ -330,6 +333,23 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
|
|||||||
displayedFailureDialog = true;
|
displayedFailureDialog = true;
|
||||||
conn.stop();
|
conn.stop();
|
||||||
|
|
||||||
|
int averageEndToEndLat = decoderRenderer.getAverageEndToEndLatency();
|
||||||
|
int averageDecoderLat = decoderRenderer.getAverageDecoderLatency();
|
||||||
|
String message = null;
|
||||||
|
if (averageEndToEndLat > 0) {
|
||||||
|
message = "Average total frame latency: "+averageEndToEndLat+" ms";
|
||||||
|
if (averageDecoderLat > 0) {
|
||||||
|
message += " (hardware decoder latency: "+averageDecoderLat+" ms)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (averageDecoderLat > 0) {
|
||||||
|
message = "Average hardware decoder latency: "+averageDecoderLat+" ms";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message != null) {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,7 +667,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, OnGenericM
|
|||||||
if (!connected && !connecting) {
|
if (!connected && !connecting) {
|
||||||
connecting = true;
|
connecting = true;
|
||||||
conn.start(PlatformBinding.getDeviceName(), holder, drFlags,
|
conn.start(PlatformBinding.getDeviceName(), holder, drFlags,
|
||||||
PlatformBinding.getAudioRenderer(), new ConfigurableDecoderRenderer());
|
PlatformBinding.getAudioRenderer(), decoderRenderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,4 +222,14 @@ public class AndroidCpuDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
public int getCapabilities() {
|
public int getCapabilities() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAverageDecoderLatency() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAverageEndToEndLatency() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,9 @@ public class ConfigurableDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
decoderRenderer.release();
|
if (decoderRenderer != null) {
|
||||||
|
decoderRenderer.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -40,4 +42,23 @@ public class ConfigurableDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
return decoderRenderer.getCapabilities();
|
return decoderRenderer.getCapabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAverageDecoderLatency() {
|
||||||
|
if (decoderRenderer != null) {
|
||||||
|
return decoderRenderer.getAverageDecoderLatency();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAverageEndToEndLatency() {
|
||||||
|
if (decoderRenderer != null) {
|
||||||
|
return decoderRenderer.getAverageEndToEndLatency();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,12 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
private boolean needsSpsNumRefFixup;
|
private boolean needsSpsNumRefFixup;
|
||||||
private VideoDepacketizer depacketizer;
|
private VideoDepacketizer depacketizer;
|
||||||
|
|
||||||
|
private long totalTimeMs;
|
||||||
|
private long decoderTimeMs;
|
||||||
|
private int totalFrames;
|
||||||
|
|
||||||
|
private final static byte[] BITSTREAM_RESTRICTIONS = new byte[] {(byte) 0xF1, (byte) 0x83, 0x2A, 0x00};
|
||||||
|
|
||||||
public static final List<String> blacklistedDecoderPrefixes;
|
public static final List<String> blacklistedDecoderPrefixes;
|
||||||
public static final List<String> spsFixupBitsreamFixupDecoderPrefixes;
|
public static final List<String> spsFixupBitsreamFixupDecoderPrefixes;
|
||||||
public static final List<String> spsFixupNumRefFixupDecoderPrefixes;
|
public static final List<String> spsFixupNumRefFixupDecoderPrefixes;
|
||||||
@ -177,6 +183,13 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
if (outIndex >= 0) {
|
if (outIndex >= 0) {
|
||||||
int lastIndex = outIndex;
|
int lastIndex = outIndex;
|
||||||
|
|
||||||
|
// Add delta time to the totals (excluding probable outliers)
|
||||||
|
long delta = System.currentTimeMillis()-(info.presentationTimeUs/1000);
|
||||||
|
if (delta > 5 && delta < 300) {
|
||||||
|
decoderTimeMs += delta;
|
||||||
|
totalTimeMs += delta;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the last output buffer in the queue
|
// Get the last output buffer in the queue
|
||||||
while ((outIndex = videoDecoder.dequeueOutputBuffer(info, 0)) >= 0) {
|
while ((outIndex = videoDecoder.dequeueOutputBuffer(info, 0)) >= 0) {
|
||||||
videoDecoder.releaseOutputBuffer(lastIndex, false);
|
videoDecoder.releaseOutputBuffer(lastIndex, false);
|
||||||
@ -216,7 +229,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
rendererThread.interrupt();
|
rendererThread.interrupt();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rendererThread.join();
|
rendererThread.join();
|
||||||
} catch (InterruptedException e) { }
|
} catch (InterruptedException e) { }
|
||||||
@ -235,48 +248,77 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
{
|
{
|
||||||
ByteBuffer buf = videoDecoderInputBuffers[inputIndex];
|
ByteBuffer buf = videoDecoderInputBuffers[inputIndex];
|
||||||
|
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
long delta = currentTime-decodeUnit.getReceiveTimestamp();
|
||||||
|
if (delta >= 0 && delta < 300) {
|
||||||
|
totalTimeMs += currentTime-decodeUnit.getReceiveTimestamp();
|
||||||
|
totalFrames++;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear old input data
|
// Clear old input data
|
||||||
buf.clear();
|
buf.clear();
|
||||||
|
|
||||||
if (needsSpsBitstreamFixup || needsSpsNumRefFixup) {
|
int codecFlags = 0;
|
||||||
|
int decodeUnitFlags = decodeUnit.getFlags();
|
||||||
|
if ((decodeUnitFlags & DecodeUnit.DU_FLAG_CODEC_CONFIG) != 0) {
|
||||||
|
codecFlags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
|
||||||
|
}
|
||||||
|
if ((decodeUnitFlags & DecodeUnit.DU_FLAG_SYNC_FRAME) != 0) {
|
||||||
|
codecFlags |= MediaCodec.BUFFER_FLAG_SYNC_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((decodeUnitFlags & DecodeUnit.DU_FLAG_CODEC_CONFIG) != 0 &&
|
||||||
|
(needsSpsBitstreamFixup || needsSpsNumRefFixup)) {
|
||||||
ByteBufferDescriptor header = decodeUnit.getBufferList().get(0);
|
ByteBufferDescriptor header = decodeUnit.getBufferList().get(0);
|
||||||
if (header.data[header.offset+4] == 0x67) {
|
if (header.data[header.offset+4] == 0x67) {
|
||||||
|
byte last = header.data[header.length+header.offset-1];
|
||||||
|
|
||||||
// TI OMAP4 requires a reference frame count of 1 to decode successfully
|
// TI OMAP4 requires a reference frame count of 1 to decode successfully
|
||||||
if (needsSpsNumRefFixup) {
|
if (needsSpsNumRefFixup) {
|
||||||
LimeLog.info("Fixing up num ref frames");
|
LimeLog.info("Fixing up num ref frames");
|
||||||
this.replace(header, 80, 9, new byte[] {0x40}, 3);
|
this.replace(header, 80, 9, new byte[] {0x40}, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
// The SPS that comes in the current H264 bytestream doesn't set bitstream_restriction_flag
|
||||||
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
// or max_dec_frame_buffering which increases decoding latency on Tegra.
|
||||||
// We manually modify the SPS here to speed-up decoding if the decoder was flagged as needing it.
|
// We manually modify the SPS here to speed-up decoding if the decoder was flagged as needing it.
|
||||||
int spsLength;
|
int spsLength;
|
||||||
if (needsSpsBitstreamFixup) {
|
if (needsSpsBitstreamFixup) {
|
||||||
switch (header.length) {
|
if (!needsSpsNumRefFixup) {
|
||||||
case 26:
|
switch (header.length) {
|
||||||
LimeLog.info("Adding bitstream restrictions to SPS (26)");
|
case 26:
|
||||||
buf.put(header.data, header.offset, 24);
|
LimeLog.info("Adding bitstream restrictions to SPS (26)");
|
||||||
buf.put((byte) 0x11);
|
buf.put(header.data, header.offset, 24);
|
||||||
buf.put((byte) 0xe3);
|
buf.put((byte) 0x11);
|
||||||
buf.put((byte) 0x06);
|
buf.put((byte) 0xe3);
|
||||||
buf.put((byte) 0x50);
|
buf.put((byte) 0x06);
|
||||||
spsLength = header.length + 2;
|
buf.put((byte) 0x50);
|
||||||
break;
|
spsLength = header.length + 2;
|
||||||
case 27:
|
break;
|
||||||
LimeLog.info("Adding bitstream restrictions to SPS (27)");
|
case 27:
|
||||||
buf.put(header.data, header.offset, 25);
|
LimeLog.info("Adding bitstream restrictions to SPS (27)");
|
||||||
buf.put((byte) 0x04);
|
buf.put(header.data, header.offset, 25);
|
||||||
buf.put((byte) 0x78);
|
buf.put((byte) 0x04);
|
||||||
buf.put((byte) 0xc1);
|
buf.put((byte) 0x78);
|
||||||
buf.put((byte) 0x94);
|
buf.put((byte) 0xc1);
|
||||||
spsLength = header.length + 2;
|
buf.put((byte) 0x94);
|
||||||
break;
|
spsLength = header.length + 2;
|
||||||
default:
|
break;
|
||||||
LimeLog.warning("Unknown SPS of length "+header.length);
|
default:
|
||||||
|
LimeLog.warning("Unknown SPS of length "+header.length);
|
||||||
|
buf.put(header.data, header.offset, header.length);
|
||||||
|
spsLength = header.length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Set bitstream restrictions to only buffer single frame
|
||||||
|
// (starts 9 bits before stop bit and 6 bits earlier because of the shortening above)
|
||||||
|
this.replace(header, header.length*8+Integer.numberOfLeadingZeros(last & - last)%8-9-6, 2, BITSTREAM_RESTRICTIONS, 3*8);
|
||||||
buf.put(header.data, header.offset, header.length);
|
buf.put(header.data, header.offset, header.length);
|
||||||
spsLength = header.length;
|
spsLength = header.length;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
buf.put(header.data, header.offset, header.length);
|
buf.put(header.data, header.offset, header.length);
|
||||||
@ -285,7 +327,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
|
|
||||||
videoDecoder.queueInputBuffer(inputIndex,
|
videoDecoder.queueInputBuffer(inputIndex,
|
||||||
0, spsLength,
|
0, spsLength,
|
||||||
0, 0);
|
currentTime * 1000, codecFlags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,7 +340,7 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
|
|
||||||
videoDecoder.queueInputBuffer(inputIndex,
|
videoDecoder.queueInputBuffer(inputIndex,
|
||||||
0, decodeUnit.getDataLength(),
|
0, decodeUnit.getDataLength(),
|
||||||
0, 0);
|
currentTime * 1000, codecFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -387,4 +429,20 @@ public class MediaCodecDecoderRenderer implements VideoDecoderRenderer {
|
|||||||
source.offset = offset;
|
source.offset = offset;
|
||||||
source.length = length;
|
source.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAverageDecoderLatency() {
|
||||||
|
if (totalFrames == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (int)(decoderTimeMs / totalFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAverageEndToEndLatency() {
|
||||||
|
if (totalFrames == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (int)(totalTimeMs / totalFrames);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user