Live video streaming application on Android
Asked Answered
E

3

11

I am trying to build a live video streaming application that streams live video from Android.

Using the MediaRecorder class, I am able to capture the video data in the form of 3gp, with h263 codecs.

However, when I run my application and stream media, I get a 2-3 second delay at the server side.

Why am I getting this delay? Are there any internal buffers that I need to flush? Are there other ways of streaming video apart from using MediaRecorder class?

Expunction answered 17/3, 2011 at 12:59 Comment(5)
Hi! I am also trying to achieve the same. Could you provide me some details how you did it with mediarecorder?Rentroll
Could you please provide some more details? Which library (ffmpeg, live555 etc...) , Which approach (RTP, RTSP ...) you use? comment by flock.duxBenjie
hi Vladimir Ivanov ....can u suggest me the whole process of live video streaming in android ..i don't know how to start with live video streaming...vv thanks to u in advance....waiting for ur reply...Mcgrody
Do you know how to send live video from android to server ? it is same as Skype.Tailrace
please help me in doing this.. I am not able to stream video to server.. If u provide ur demo code.. it ll b very help full thanks in advanceDefect
T
1

If you're set on RTMP streaming from Android, the best solution is MediaCodec + FFmpeg + librtmp. This avoids any hacky "detect the NAL Unit within the bytestream" business but requires Android 4.3. Skate where the puck is going...

I've developed an open source SDK that demonstrates RTMP streaming with FFmpeg + librtmp as pre-built shared libraries. The SDK is focused on HLS streaming, but RTMP support is present.

If you'd like help building FFmpeg yourself for Android (with or without librtmp), check out my guide.

Tildie answered 14/5, 2014 at 23:8 Comment(2)
is it working without kickflip account? can i stream to any HLS-client?Streamy
Sure! Try using an AVRecorder.java with a HLSFileMonitor.java to monitor when .ts segments and .m3u8 files are ready for upload. Broadcaster.java is the Kickflip reference implementation.Tildie
P
0

If the Android app works well, and the code it's optimitzed, provably the reason of that delay is that you are seding heavy data to server and the HTTP request to a server have a limit of MB to be send. When that happends the class automaticly or the programer must fractionate the HTTP request to multiple HTTP requests and obviously it's slower.

Ploss answered 17/2, 2014 at 11:21 Comment(0)
B
-3

first create this class.

MediaPlayerDemo_Video.java:-


package com.videostreaming.player;

import android.app.Activity;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;


public class MediaPlayerDemo_Video extends Activity implements
        OnBufferingUpdateListener, OnCompletionListener,
        OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback {

     private String path1 = "http://podcast.20min-tv.ch/podcast/20min/199733.mp4";
    // private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199752.mp4";
     private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199693.mp4";
     private String path = "";

    private static final String TAG = "MediaPlayerDemo";
    private int mVideoWidth;
    private int mVideoHeight;
    private MediaPlayer mMediaPlayer;
    private SurfaceView mPreview;
    private SurfaceHolder holder;
//    private String path;
    private Bundle extras;
    private static final String MEDIA = "media";
    private static final int LOCAL_AUDIO = 1;
    private static final int STREAM_AUDIO = 2;
    private static final int RESOURCES_AUDIO = 3;
    private static final int LOCAL_VIDEO = 4;
    private static final int STREAM_VIDEO = 5;
    private boolean mIsVideoSizeKnown = false;
    private boolean mIsVideoReadyToBePlayed = false;

    private Bundle bdlReceivedData = null;
    private Intent self = null;

    /**
     * 
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.mediaplayer_2);

        mPreview = (SurfaceView) findViewById(R.id.surface);
        holder = mPreview.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        extras = getIntent().getExtras();

        self = this.getIntent();
        bdlReceivedData = self.getExtras();

        if (bdlReceivedData != null && bdlReceivedData.getInt("video") > 0)
        {
            if (bdlReceivedData.getInt("video") == 1)
            {
                Toast.makeText(MediaPlayerDemo_Video.this,"playing Video 1", Toast.LENGTH_SHORT);
                path = path1;
            }
            else if (bdlReceivedData.getInt("video") == 2)
            {
                Toast.makeText(MediaPlayerDemo_Video.this,"playing Video 2", Toast.LENGTH_SHORT);
                path = path2;
            }
        }
    }

    private void playVideo(Integer Media) {
        doCleanUp();
        try {

//            switch (Media) {
//                case LOCAL_VIDEO:
//                    /*
//                     * TODO: Set the path variable to a local media file path.
//                     */
//                    path = "";
//                    if (path == "") {
//                        // Tell the user to provide a media file URL.
//                        Toast
//                                .makeText(
//                                        MediaPlayerDemo_Video.this,
//                                        "Please edit MediaPlayerDemo_Video Activity, "
//                                                + "and set the path variable to your media file path."
//                                                + " Your media file must be stored on sdcard.",
//                                        Toast.LENGTH_LONG).show();
//
//                    }
//                    break;
//                case STREAM_VIDEO:
//                    /*
//                     * TODO: Set path variable to progressive streamable mp4 or
//                     * 3gpp format URL. Http protocol should be used.
//                     * Mediaplayer can only play "progressive streamable
//                     * contents" which basically means: 1. the movie atom has to
//                     * precede all the media data atoms. 2. The clip has to be
//                     * reasonably interleaved.
//                     * 
//                     */
//                    path = "";
//                    if (path == "") {
//                        // Tell the user to provide a media file URL.
//                        Toast
//                                .makeText(
//                                        MediaPlayerDemo_Video.this,
//                                        "Please edit MediaPlayerDemo_Video Activity,"
//                                                + " and set the path variable to your media file URL.",
//                                        Toast.LENGTH_LONG).show();
//
//                    }
//
//                    break;
//
//
//            }

            // Create a new media player and set the listeners
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setDataSource(path);
            mMediaPlayer.setDisplay(holder);
            mMediaPlayer.prepare();
            mMediaPlayer.setOnBufferingUpdateListener(this);
            mMediaPlayer.setOnCompletionListener(this);
            mMediaPlayer.setOnPreparedListener(this);
            mMediaPlayer.setOnVideoSizeChangedListener(this);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

        } catch (Exception e) {
            Log.e(TAG, "error: " + e.getMessage(), e);
        }
    }

    public void onBufferingUpdate(MediaPlayer arg0, int percent) {
        Log.d(TAG, "onBufferingUpdate percent:" + percent);

    }

    public void onCompletion(MediaPlayer arg0) {
        Log.d(TAG, "onCompletion called");
    }

    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
        Log.v(TAG, "onVideoSizeChanged called");
        if (width == 0 || height == 0) {
            Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")");
            return;
        }
        mIsVideoSizeKnown = true;
        mVideoWidth = width;
        mVideoHeight = height;
        if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
            startVideoPlayback();
        }
    }

    public void onPrepared(MediaPlayer mediaplayer) {
        Log.d(TAG, "onPrepared called");
        mIsVideoReadyToBePlayed = true;
        if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown) {
            startVideoPlayback();
        }
    }

    public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
        Log.d(TAG, "surfaceChanged called");

    }

    public void surfaceDestroyed(SurfaceHolder surfaceholder) {
        Log.d(TAG, "surfaceDestroyed called");
    }


    public void surfaceCreated(SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated called");
        playVideo(extras.getInt(MEDIA));
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaPlayer();
        doCleanUp();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        releaseMediaPlayer();
        doCleanUp();
    }

    private void releaseMediaPlayer() {
        if (mMediaPlayer != null) {
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }

    private void doCleanUp() {
        mVideoWidth = 0;
        mVideoHeight = 0;
        mIsVideoReadyToBePlayed = false;
        mIsVideoSizeKnown = false;
    }

    private void startVideoPlayback() {
        Log.v(TAG, "startVideoPlayback");
        holder.setFixedSize(mVideoWidth, mVideoHeight);
        mMediaPlayer.start();
    }
}

now the next class

MainMenu.java


package com.videostreaming.player;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainMenu extends Activity {

    Button btn_videoViewDemo1;
    Button btn_videoViewDemo2;
    Button btn_MediaPlayerDemo1;    
    Button btn_MediaPlayerDemo2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn_videoViewDemo1 = (Button)findViewById(R.id.btn_videoViewDemo1);
        btn_videoViewDemo2 = (Button)findViewById(R.id.btn_videoViewDemo2);
        btn_MediaPlayerDemo1 = (Button)findViewById(R.id.btn_MediaPlayerDemo1);
        btn_MediaPlayerDemo2 = (Button)findViewById(R.id.btn_MediaPlayerDemo2);

        btn_videoViewDemo1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent Navigation1 = new Intent(MainMenu.this,streamplayer.class);
                Navigation1.putExtra("video",1);
                startActivity(Navigation1);             
            }
        });

        btn_videoViewDemo2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent Navigation1 = new Intent(MainMenu.this,streamplayer.class);
                Navigation1.putExtra("video",2);
                startActivity(Navigation1);
            }
        });

        btn_MediaPlayerDemo1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent Navigation1 = new Intent(MainMenu.this,MediaPlayerDemo_Video.class);
                Navigation1.putExtra("video",1);
                startActivity(Navigation1);             
            }
        });

        btn_MediaPlayerDemo2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent Navigation1 = new Intent(MainMenu.this,MediaPlayerDemo_Video.class);
                Navigation1.putExtra("video",2);
                startActivity(Navigation1);             
            }
        });     
    }
}

streamplayer.java

package com.videostreaming.player;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;

public class streamplayer extends Activity {
    /** Called when the activity is first created. */

     private String path1 = "http://podcast.20min-tv.ch/podcast/20min/199733.mp4";
     //private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199752.mp4";
     private String path2 = "http://podcast.20min-tv.ch/podcast/20min/199693.mp4";
     private String path = "";

     //// Method 1 - Default Method
     private VideoView mVideoView;

     private Bundle bdlReceivedData = null;
     private Intent self = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try
        {
            setContentView(R.layout.videoview);
            mVideoView = (VideoView) findViewById(R.id.surface_view);

            self = this.getIntent();
            bdlReceivedData = self.getExtras();

            if (bdlReceivedData != null && bdlReceivedData.getInt("video") > 0)
            {
                if (bdlReceivedData.getInt("video") == 1)
                {
                    Toast.makeText(streamplayer.this,"playing Video 1", Toast.LENGTH_SHORT);
                    path = path1;
                }
                else if (bdlReceivedData.getInt("video") == 2)
                {
                    Toast.makeText(streamplayer.this,"playing Video 2", Toast.LENGTH_SHORT);
                    path = path2;
                }

                /*
                 * Alternatively,for streaming media you can use
                 * mVideoView.setVideoURI(Uri.parse(URLstring));
                 */

                //mVideoView.setVideoPath(path1);
                ///ELSE
                mVideoView.setVideoURI(Uri.parse(path));                
                mVideoView.setMediaController(new MediaController(this));
                mVideoView.requestFocus();              
                mVideoView.postInvalidateDelayed(100);        
                mVideoView.start();

            }

        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            Toast.makeText(streamplayer.this,"Error Occured:- " + e.getMessage(),Toast.LENGTH_SHORT).show();
        } 
    }
}

mediaplayer_2.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <SurfaceView android:id="@+id/surface"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center">
    </SurfaceView>

</LinearLayout>

videoview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <VideoView 
        android:id="@+id/surface_view" 
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"/>

</LinearLayout>

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"/>

    <Button
        android:id="@+id/btn_videoViewDemo1"
        android:layout_width="fill_parent"
        android:layout_height="40dip"
        android:text="VideoView1"
        android:layout_margin="10dip">
    </Button>

    <Button
        android:id="@+id/btn_videoViewDemo2"
        android:layout_width="fill_parent"
        android:layout_height="40dip"
        android:text="VideoView2"
        android:layout_margin="10dip">
    </Button>

    <Button
        android:id="@+id/btn_MediaPlayerDemo1"
        android:layout_width="fill_parent"
        android:layout_height="40dip"
        android:text="MediaPlayerDemo1"
        android:layout_margin="10dip">
    </Button>



    <Button
        android:id="@+id/btn_MediaPlayerDemo2"
        android:layout_width="fill_parent"
        android:layout_height="40dip"
        android:text="MediaPlayerDemo2"
        android:layout_margin="10dip">
    </Button>


</LinearLayout>
Brazenfaced answered 5/5, 2011 at 6:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.