2017-02-22 1 views
0

Je travaille sur une application qui enregistre l'écran de mon appareil Android et le transmet via RTSP à un autre client. J'utilise VirtualDisplay et MediaCodec pour cela.Streaming Android avec MediaCodec et VirtualDisplay, clients déconnectés

J'ai un problème que je ne sais pas comment résoudre. Quand je commence le streaming, le client ne reçoit rien jusqu'à ce que l'écran change. Je suppose que c'est logique, le tampon ne contient rien, donc rien n'est envoyé au client. Le code pour cela est le suivant:

MediaCodec buildMediaCodec() throws IOException { 
    MediaFormat format = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, VIDEO_WIDTH, VIDEO_HEIGHT); 

    // Set some required properties. The media codec may fail if these aren't defined. 
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); 
    format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); 
    format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE); 
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 1 seconds between I-frames 

    // Create a MediaCodec encoder and configure it. Get a Surface we can use for recording into. 
    MediaCodec mediaCodec = MediaCodec.createEncoderByType(VIDEO_MIME_TYPE); 
    mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 
    return mediaCodec; 
} 

// This is passed to buildVirtualDisplay(), and I get it from calling buildMediaCodec() 
Surface mediaCodecSurface = mMediaCodec.createInputSurface(); 

VirtualDisplay buildVirtualDisplay(MediaProjection mediaProjection, Surface mediaCodecSurface, DisplayMetrics displayMetrics) { 
    if (mediaProjection == null || mediaCodecSurface == null || displayMetrics == null) { 
     throw new InvalidParameterException("MediaProjection, Surface and DisplayMetrics are mandatory"); 
    } 
    return mediaProjection.createVirtualDisplay("Recording Display", VIDEO_WIDTH, VIDEO_HEIGHT, SCREEN_DPI, 0 /* flags */, mediaCodecSurface, null /* callback */, null /* handler */); 
} 

... 

mIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 500000); 
if (mIndex >= 0) { 
    mBuffer = mMediaCodec.getOutputBuffer(mIndex); 
    if (mBuffer == null) { 
     throw new RuntimeException("couldn't fetch buffer at index " + mIndex); 
    } 
    mBuffer.position(0); 
    break; 
} else if (mIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
    mMediaFormat = mMediaCodec.getOutputFormat(); 
    Log.i(TAG, mMediaFormat.toString()); 
} else if (mIndex == MediaCodec.INFO_TRY_AGAIN_LATER) { 
    Log.v(TAG, "No buffer available..."); 
} else { 
    Log.e(TAG, "Message: " + mIndex); 
} 

Dans les journaux, je peux voir Aucun tampon disponible ... l'un après l'autre. Au moment où l'écran change, il s'arrête.

Le problème est lorsque j'arrête d'interagir avec le téléphone. L'écran n'est pas actualisé car rien ne change, donc je continue d'obtenir MediaCodec.INFO_TRY_AGAIN_LATER. Après 10 secondes environ, le client se déconnecte. Je suppose qu'il ne reçoit rien alors il arrête simplement la connexion.

J'ai également observé que plus j'attends au début, plus le délai entre le serveur et les périphériques clients est important.

Si je mets une barre de progression tout va bien, il semble que l'écran soit de nouveau rendu afin que le tampon contienne des données à envoyer.

J'ai cherché des informations sur ce problème. Toute suggestion de ce que je pourrais faire pour empêcher cela de se produire? Dois-je utiliser une autre surface entre MediaCodec et VirtualDisplay et essayer de "forcer" le rendu?

Merci.

Répondre

1

J'ai découvert que le client se déconnecte après n'avoir pas reçu de données pendant au moins 10 secondes. J'essaye KEY_REPEAT_PREVIOUS_FRAME_AFTER de MediaFormat pour empêcher ceci, mais jusqu'ici aucune chance.

+0

Avez-vous déjà trouvé comment résoudre ce problème? –

+1

Non, je l'ai piraté. Je montre une icône sur la barre d'état. Cette icône est animée. J'ai un drawable avec deux images, ces deux images sont les mêmes, donc l'utilisateur ne voit rien changer. Mais pour Android, il doit "repeindre" cette partie, donc il continue à générer des images. –

+0

haha ​​intelligent :) merci! –