Android Barcode Scanner using IP Camera

An IP camera, also known as a network camera, is a digital video tool that sends and receives data via the internet. Unlike its analogue predecessor, the CCTV (Closed Circuit TV), it offers the functionality to view live or recorded footage from anywhere, anytime using a web-based platform or mobile application.

IP cameras are widely used in surveillance. They can also be used for inventory management or serve as an extra camera for devices like Android tablets and kiosks.

In this article, we are going to create an Android barcode scanner using an IP camera. ExoPlayer is used to play the camera stream of IP cameras via RTSP and Dynamsoft Barcode Reader is used for barcode scanning.

Keywords explaination:

  • RTSP (Real-Time Streaming Protocol) is a protocol for streaming media through the network.
  • ExoPlayer is an extensible media player for Android which supports RTSP.

New Project

Use Android Studio to create an app project with an empty activity.

Add Dependencies

  1. Add ExoPlayer in your app’s build.gradle.

    implementation "androidx.media3:media3-exoplayer:1.4.1"
    implementation "androidx.media3:media3-exoplayer-dash:1.4.1"
    implementation "androidx.media3:media3-ui:1.4.1"
    implementation "androidx.media3:media3-exoplayer-rtsp:1.4.1"
    
  2. Add Dynamsoft Barcode Reader.

    1. Open settings.gradle to add Dynamsoft’s maven repo.

      dependencyResolutionManagement {
          repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
          repositories {
              google()
              mavenCentral()
              maven {
                  url "https://download2.dynamsoft.com/maven/aar"
              }
          }
      }
      
    2. Declare the dependency in the app’s build.gradle.

      implementation 'com.dynamsoft:dynamsoftbarcodereaderbundle:10.4.2000'
      

Add Permissions

Open AndroidManifest.xml to add the Internet permission.

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

Use ExoPlayer to Play the IP Camera’s RTSP Stream

  1. Open activity_main.xml to add the PlayerView.

    <androidx.media3.ui.PlayerView
        android:id="@+id/playerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:surface_type="surface_view" >
    </androidx.media3.ui.PlayerView>
    

    Get the view in MainActivity.java.

    private PlayerView playerView;
    playerView = findViewById(R.id.playerView);
    
  2. Create an instance of ExoPlayer and set it as PlayerView’s player.

    ExoPlayer player = new ExoPlayer.Builder(getApplicationContext()).build();
    playerView.setPlayer(player);
    
  3. Set the RTSP stream as the media source for the player. You can start a local RTSP server using mediamtx for testing.

    protected Uri uri = Uri.parse("rtsp://192.168.8.65:8554/mystream");
    MediaSource mediaSource =
                 new RtspMediaSource.Factory()
                    .createMediaSource(MediaItem.fromUri(uri));
    player.setMediaSource(mediaSource);
    
  4. Prepare the player and play the stream when it is ready.

    player.setPlayWhenReady(true);
    player.prepare();
    

Read Barcodes from the IP Camera

  1. Initialize the license for Dynamsoft Barcode Reader. You can apply for a license here.

    LicenseManager.initLicense("DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==", this, (isSuccess, error) -> {
        if (!isSuccess) {
            error.printStackTrace();
        }
    });
    
  2. Create an instance of capture vision router to perform the barcode reading.

    private CaptureVisionRouter mRouter;
    mRouter = new CaptureVisionRouter(this);
    
  3. Start a timer to capture frames of the IP camera stream and read barcodes from them. Display the result in a TextView.

    private boolean decoding = false;
    private boolean isVideoPlaying = false;
    private Timer timer = null;
    private void startDecoding(){
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                takePhotoAndDecode();
            }
        };
        timer = new Timer();
        timer.schedule(task, 1000,100);
    }
       
     @OptIn(markerClass = UnstableApi.class)
     @SuppressLint("NewApi")
     private void takePhotoAndDecode() {
        if (decoding == false && isVideoPlaying) {
            decoding = true;
            SurfaceView surfaceView = (SurfaceView) playerView.getVideoSurfaceView();
            // Create a bitmap the size of the scene view.
            final Bitmap bitmap = Bitmap.createBitmap(surfaceView.getWidth(), surfaceView.getHeight(),
                    Bitmap.Config.ARGB_8888);
            // Create a handler thread to offload the processing of the image.
            final HandlerThread handlerThread = new HandlerThread("PixelCopier");
            handlerThread.start();
            // Make the request to copy.
            PixelCopy.request(surfaceView, bitmap, (copyResult) -> {
                if (copyResult == PixelCopy.SUCCESS) {
                    CapturedResult result =  mRouter.capture(bitmap, EnumPresetTemplate.PT_READ_BARCODES);
                    DecodedBarcodesResult decodedBarcodesResult = result.getDecodedBarcodesResult();
                    if (decodedBarcodesResult != null) {
                        BarcodeResultItem[] items = decodedBarcodesResult.getItems();
                        StringBuilder sb = new StringBuilder();
                        for (BarcodeResultItem item:items) {
                            sb.append(item.getFormatString());
                            sb.append(": ");
                            sb.append(item.getText());
                            sb.append("\n");
                        }
                        runOnUiThread(new Runnable() {
                            public void run() {
                                textView.setText(sb.toString());
                            }
                        });
                    }
                }
                decoding = false;
                handlerThread.quitSafely();
            }, new Handler(handlerThread.getLooper()));
        }
    }
    
  4. We can check whether the video is playing by adding a listener for the player.

    player.addListener(
        new Player.Listener() {
            @Override
            public void onIsPlayingChanged(boolean isPlaying) {
                isVideoPlaying = isPlaying;
            }
        });
    

All right, we’ve now completed the demo.

Source Code

Check out the source code of the demo to have a try:

https://github.com/tony-xlh/IPCam-Barcode-Scanner-Android