mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 11:33:06 +00:00
Refactor the video decoding path so the DecoderRenderer handles pulling decode units instead of dedicating a separate thread for this
This commit is contained in:
parent
7b10e52808
commit
38423a9f37
@ -1,24 +1,17 @@
|
|||||||
package com.limelight.nvstream.av.video;
|
package com.limelight.nvstream.av.video;
|
||||||
|
|
||||||
import com.limelight.nvstream.av.DecodeUnit;
|
|
||||||
|
|
||||||
public interface VideoDecoderRenderer {
|
public interface VideoDecoderRenderer {
|
||||||
public static final int FLAG_PREFER_QUALITY = 0x1;
|
public static final int FLAG_PREFER_QUALITY = 0x1;
|
||||||
public static final int FLAG_FORCE_HARDWARE_DECODING = 0x2;
|
public static final int FLAG_FORCE_HARDWARE_DECODING = 0x2;
|
||||||
public static final int FLAG_FORCE_SOFTWARE_DECODING = 0x4;
|
public static final int FLAG_FORCE_SOFTWARE_DECODING = 0x4;
|
||||||
|
|
||||||
// SubmitDecodeUnit() is lightweight, so don't use an extra thread for decoding
|
|
||||||
public static final int CAPABILITY_DIRECT_SUBMIT = 0x1;
|
|
||||||
|
|
||||||
public int getCapabilities();
|
public int getCapabilities();
|
||||||
|
|
||||||
public void setup(int width, int height, int redrawRate, Object renderTarget, int drFlags);
|
public void setup(int width, int height, int redrawRate, Object renderTarget, int drFlags);
|
||||||
|
|
||||||
public void start();
|
public void start(VideoDepacketizer depacketizer);
|
||||||
|
|
||||||
public void stop();
|
public void stop();
|
||||||
|
|
||||||
public void release();
|
public void release();
|
||||||
|
|
||||||
public boolean submitDecodeUnit(DecodeUnit decodeUnit);
|
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,12 @@ public class VideoDepacketizer {
|
|||||||
private ByteBufferDescriptor cachedDesc = new ByteBufferDescriptor(null, 0, 0);
|
private ByteBufferDescriptor cachedDesc = new ByteBufferDescriptor(null, 0, 0);
|
||||||
|
|
||||||
private ConnectionStatusListener controlListener;
|
private ConnectionStatusListener controlListener;
|
||||||
private VideoDecoderRenderer directSubmitDr;
|
|
||||||
|
|
||||||
private static final int DU_LIMIT = 15;
|
private static final int DU_LIMIT = 15;
|
||||||
private LinkedBlockingQueue<DecodeUnit> decodedUnits = new LinkedBlockingQueue<DecodeUnit>(DU_LIMIT);
|
private LinkedBlockingQueue<DecodeUnit> decodedUnits = new LinkedBlockingQueue<DecodeUnit>(DU_LIMIT);
|
||||||
|
|
||||||
public VideoDepacketizer(VideoDecoderRenderer directSubmitDr, ConnectionStatusListener controlListener)
|
public VideoDepacketizer(ConnectionStatusListener controlListener)
|
||||||
{
|
{
|
||||||
this.directSubmitDr = directSubmitDr;
|
|
||||||
this.controlListener = controlListener;
|
this.controlListener = controlListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,11 +66,7 @@ public class VideoDepacketizer {
|
|||||||
|
|
||||||
// Construct the H264 decode unit
|
// Construct the H264 decode unit
|
||||||
DecodeUnit du = new DecodeUnit(DecodeUnit.TYPE_H264, avcFrameDataChain, avcFrameDataLength, flags, frameNumber);
|
DecodeUnit du = new DecodeUnit(DecodeUnit.TYPE_H264, avcFrameDataChain, avcFrameDataLength, flags, frameNumber);
|
||||||
if (directSubmitDr != null) {
|
if (!decodedUnits.offer(du)) {
|
||||||
// Submit directly to the decoder
|
|
||||||
directSubmitDr.submitDecodeUnit(du);
|
|
||||||
}
|
|
||||||
else if (!decodedUnits.offer(du)) {
|
|
||||||
LimeLog.warning("Video decoder is too slow! Forced to drop decode units");
|
LimeLog.warning("Video decoder is too slow! Forced to drop decode units");
|
||||||
|
|
||||||
// Invalidate all frames from the start of the DU queue
|
// Invalidate all frames from the start of the DU queue
|
||||||
@ -92,7 +86,7 @@ public class VideoDepacketizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInputDataSlow(VideoPacket packet, ByteBufferDescriptor location)
|
private void addInputDataSlow(VideoPacket packet, ByteBufferDescriptor location)
|
||||||
{
|
{
|
||||||
while (location.length != 0)
|
while (location.length != 0)
|
||||||
{
|
{
|
||||||
@ -175,7 +169,7 @@ public class VideoDepacketizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInputDataFast(VideoPacket packet, ByteBufferDescriptor location, boolean firstPacket)
|
private void addInputDataFast(VideoPacket packet, ByteBufferDescriptor location, boolean firstPacket)
|
||||||
{
|
{
|
||||||
if (firstPacket) {
|
if (firstPacket) {
|
||||||
// Setup state for the new frame
|
// Setup state for the new frame
|
||||||
@ -340,10 +334,15 @@ public class VideoDepacketizer {
|
|||||||
addInputData(new VideoPacket(rtpPayload));
|
addInputData(new VideoPacket(rtpPayload));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecodeUnit getNextDecodeUnit() throws InterruptedException
|
public DecodeUnit takeNextDecodeUnit() throws InterruptedException
|
||||||
{
|
{
|
||||||
return decodedUnits.take();
|
return decodedUnits.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DecodeUnit pollNextDecodeUnit()
|
||||||
|
{
|
||||||
|
return decodedUnits.poll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NAL {
|
class NAL {
|
||||||
|
@ -13,7 +13,6 @@ import java.util.LinkedList;
|
|||||||
import com.limelight.nvstream.NvConnectionListener;
|
import com.limelight.nvstream.NvConnectionListener;
|
||||||
import com.limelight.nvstream.StreamConfiguration;
|
import com.limelight.nvstream.StreamConfiguration;
|
||||||
import com.limelight.nvstream.av.ByteBufferDescriptor;
|
import com.limelight.nvstream.av.ByteBufferDescriptor;
|
||||||
import com.limelight.nvstream.av.DecodeUnit;
|
|
||||||
import com.limelight.nvstream.av.RtpPacket;
|
import com.limelight.nvstream.av.RtpPacket;
|
||||||
import com.limelight.nvstream.av.ConnectionStatusListener;
|
import com.limelight.nvstream.av.ConnectionStatusListener;
|
||||||
|
|
||||||
@ -140,12 +139,7 @@ public class VideoStream {
|
|||||||
decRend.setup(streamConfig.getWidth(), streamConfig.getHeight(),
|
decRend.setup(streamConfig.getWidth(), streamConfig.getHeight(),
|
||||||
60, renderTarget, drFlags);
|
60, renderTarget, drFlags);
|
||||||
|
|
||||||
if ((decRend.getCapabilities() & VideoDecoderRenderer.CAPABILITY_DIRECT_SUBMIT) != 0) {
|
depacketizer = new VideoDepacketizer(avConnListener);
|
||||||
depacketizer = new VideoDepacketizer(decRend, avConnListener);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
depacketizer = new VideoDepacketizer(null, avConnListener);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,44 +167,12 @@ public class VideoStream {
|
|||||||
// early packets
|
// early packets
|
||||||
startReceiveThread();
|
startReceiveThread();
|
||||||
|
|
||||||
// Start a decode thread if we're not doing direct submit
|
|
||||||
if ((decRend.getCapabilities() & VideoDecoderRenderer.CAPABILITY_DIRECT_SUBMIT) == 0) {
|
|
||||||
startDecoderThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the renderer
|
// Start the renderer
|
||||||
decRend.start();
|
decRend.start(depacketizer);
|
||||||
startedRendering = true;
|
startedRendering = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startDecoderThread()
|
|
||||||
{
|
|
||||||
Thread t = new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Read the decode units generated from the RTP stream
|
|
||||||
while (!isInterrupted())
|
|
||||||
{
|
|
||||||
DecodeUnit du;
|
|
||||||
|
|
||||||
try {
|
|
||||||
du = depacketizer.getNextDecodeUnit();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
listener.connectionTerminated(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
decRend.submitDecodeUnit(du);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
threads.add(t);
|
|
||||||
t.setName("Video - Decoder");
|
|
||||||
t.setPriority(Thread.MAX_PRIORITY);
|
|
||||||
t.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startReceiveThread()
|
private void startReceiveThread()
|
||||||
{
|
{
|
||||||
// Receive thread
|
// Receive thread
|
||||||
|
Loading…
x
Reference in New Issue
Block a user