Hello Tello Pilot!
Join our DJI Tello community & remove this banner.
Sign up

Help with video stream in Android

Harshith

Member
Joined
Aug 6, 2020
Messages
7
Reaction score
0
Location
India
I just want to solve a small problem which is troubling me.
I'm getting the bytes, and also rendering it onto the surface.
Please look at this video:
As you can see, I'm getting only the upper part of the stream as desired and also only if I move my Tello continuously.
Can anyone help me with this please.
My source code:
Java:
package Hello.Tello;

import android.app.Activity;
import android.app.*;
import android.os.*;
import android.view.*;
import android.view.View.*;
import android.widget.*;
import android.content.*;
import android.content.res.*;
import android.graphics.*;
import android.graphics.drawable.*;
import android.media.*;
import android.net.*;
import android.text.*;
import android.text.style.*;
import android.util.*;
import android.webkit.*;
import android.animation.*;
import android.view.animation.*;
import java.util.*;
import java.util.regex.*;
import java.text.*;
import org.json.*;
import android.widget.LinearLayout;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.DialogFragment;
import java.net.*;
import java.io.*;
import java.nio.ByteBuffer;

public class MainActivity extends  Activity {
  
  
    private  MediaCodec m_codec;
    private  DecodeFramesTask m_frameTask;
    private  H264Provider provider;
    private  InetAddress mainIp;
  
    private LinearLayout linear1;
    private TextureView m_surface;
    @Override
    protected void onCreate(Bundle _savedInstanceState) {
        super.onCreate(_savedInstanceState);
        setContentView(R.layout.main);
        initialize(_savedInstanceState);
        initializeLogic();
    }
  
    private void initialize(Bundle _savedInstanceState) {
      
        linear1 = (LinearLayout) findViewById(R.id.linear1);
        m_surface = (TextureView) findViewById(R.id.m_surface);
    }
  
    private void initializeLogic() {
        try{
                mainIp = InetAddress.getByName("192.168.10.1");
        }catch(Exception e){}
        _extra();
        m_surface.setSurfaceTextureListener(new TextureView.SurfaceTextureListener(){
                public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                        provider = new H264Provider();
                        provider.execute();
                        MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 360);
                        format.setByteBuffer("csd-0", ByteBuffer.wrap(provider.csd0));
                        format.setByteBuffer("csd-1", ByteBuffer.wrap(provider.csd1));
                        format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 960*720);
                        try {
                                m_codec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
                                m_codec.configure(format, new Surface(m_surface.getSurfaceTexture()), null, 0);
                                m_codec.start();
                                m_frameTask = new DecodeFramesTask();
                                m_frameTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                            }catch(Exception e){
                                Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
                            }
                }
              
                public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
                }
              
                public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                        return false;
                }
              
                public void onSurfaceTextureUpdated(SurfaceTexture surface) {
                }
        });
    }
  
    @Override
    protected void onActivityResult(int _requestCode, int _resultCode, Intent _data) {
      
        super.onActivityResult(_requestCode, _resultCode, _data);
      
        switch (_requestCode) {
          
            default:
            break;
        }
    }
  
    public void _extra () {
        new Thread(new Runnable(){
                @Override
                public void run(){
                        try{
                                DatagramSocket socket = new DatagramSocket(8889);
                                DatagramPacket packet1 = new DatagramPacket("command".getBytes(), "command".getBytes().length, mainIp, 8889);
                                DatagramPacket packet2 = new DatagramPacket("streamon".getBytes(), "streamon".getBytes().length, mainIp, 8889);
                                socket.send(packet1);
                                socket.send(packet2);
                            }catch(Exception e){Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();}
                    }
        }).start();
    }
  
    private class DecodeFramesTask extends AsyncTask<String, String, String> {
            @Override
            protected String doInBackground(String... data) {
                    while(!isCancelled()) {
                            byte[] frame = provider.nextFrame();
                            int inputIndex = m_codec.dequeueInputBuffer(-1);
                            if(inputIndex>=0) {
                                    ByteBuffer buffer = m_codec.getInputBuffer(inputIndex);
                                    buffer.put(frame);
                                    m_codec.queueInputBuffer(inputIndex, 0, frame.length, 0, 0);
                            }
                          
                            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                            int outputIndex = m_codec.dequeueOutputBuffer(info, 0);
                            if (outputIndex >= 0) {
                                    m_codec.releaseOutputBuffer(outputIndex, true);
                            }
                    }
                    return "";
            }
    }
  
    private class H264Provider extends AsyncTask<String, String, String> {
            public byte[] frame = new byte[960*720];
            private DatagramSocket socket;
            private InetSocketAddress address;
            public byte[] csd0 = {0, 0, 0, 1, 103, 66, 0, 42, (byte) 149, (byte) 168, 30, 0, (byte) 137, (byte) 249, 102, (byte) 224, 32, 32, 32, 64};
            public byte[] csd1 = {0, 0, 0, 1, 104, (byte) 206, 60, (byte) 128, 0, 0, 0, 1, 6, (byte) 229, 1, (byte) 151, (byte) 128};
          
            public H264Provider(){
                    try{
                            socket = new DatagramSocket(11111);
                    }catch(Exception e){Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();}
            }
          
            @Override
            protected String doInBackground(String... data) {
                    while(!isCancelled()) {
                            DatagramPacket packet = new DatagramPacket(frame, frame.length);
                            try{
                                    socket.receive(packet);
                            }catch(Exception e){Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();}
                            frame = packet.getData();
                    }
                    return "";
            }
          
            public byte[] nextFrame(){
                    return frame;
            }
          
            public void release(){
                    m_codec.stop();
                    m_codec.release();
                    socket.close();
                    m_frameTask.cancel(true);
                    this.cancel(true);
            }
    }
  
  
  
    @Deprecated
    public void showMessage(String _s) {
        Toast.makeText(getApplicationContext(), _s, Toast.LENGTH_SHORT).show();
    }
  
    @Deprecated
    public int getLocationX(View _v) {
        int _location[] = new int[2];
        _v.getLocationInWindow(_location);
        return _location[0];
    }
  
    @Deprecated
    public int getLocationY(View _v) {
        int _location[] = new int[2];
        _v.getLocationInWindow(_location);
        return _location[1];
    }
  
    @Deprecated
    public int getRandom(int _min, int _max) {
        Random random = new Random();
        return random.nextInt(_max - _min + 1) + _min;
    }
  
    @Deprecated
    public ArrayList<Double> getCheckedItemPositionsToArray(ListView _list) {
        ArrayList<Double> _result = new ArrayList<Double>();
        SparseBooleanArray _arr = _list.getCheckedItemPositions();
        for (int _iIdx = 0; _iIdx < _arr.size(); _iIdx++) {
            if (_arr.valueAt(_iIdx))
            _result.add((double)_arr.keyAt(_iIdx));
        }
        return _result;
    }
  
    @Deprecated
    public float getDip(int _input){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, _input, getResources().getDisplayMetrics());
    }
  
    @Deprecated
    public int getDisplayWidthPixels(){
        return getResources().getDisplayMetrics().widthPixels;
    }
  
    @Deprecated
    public int getDisplayHeightPixels(){
        return getResources().getDisplayMetrics().heightPixels;
    }
  
}

Please don't care about extras. Only H264Provider task, DecodeFramesTask and initializeLogic() are the part of video streaming. Please help me with this.
Thankyou
Please note: I'm 15 years and I'm still learning.
 
Last edited:

Harshith

Member
Joined
Aug 6, 2020
Messages
7
Reaction score
0
Location
India
Ive figured out that I'm not combining the slices into the frame. I'm just rendering the slices 😅. But ive tried combining the frames, but now the app has been crashing. Can someone give a more detailed information regarding the video stream?

Thanks
Harshith
 

New Threads

Members online

Forum statistics

Threads
5,108
Messages
36,932
Members
13,804
Latest member
Dnexus