Developer Jun 22, 2022

How to Make a Movie-Watching App in a Few Hours

Download Demo & Source Code →

Talk to an Expert

Since my girlfriend and I reside in different cities, we don't get to spend much time in each other's physical company. When we were on video chat one day, she said: "Hey, it's been a while since the two of us went to the cinema together. When can we watch do that again... "

She had a point. It's been quite some time...

Though we couldn't see each other right away, we could watch a movie together online. I am aware that there are several apps available to achieve that. More and more of these apps and services have come out to help people stay in touch, especially since the pandemic started. Then it occured to me that, wouldn't it be cool if I made an exclusive app just for the two of us?

I have everything I need to build such an app, as the company I work for, ZEGOCLOUD, is the cloud-based RTC API platform that allows developers easily integrate real-time audio/video and in-app chat features into any app.

So I went on staring my little project.
...

A few hours later, I got this:

As a developer, I enjoy constructing things and discussing how they are made. To help you better understand the implementation, I'm going to detail some of the most significant processes in the following parts.

The implementation

Set up the development environment

  • Android Studio (version 2.1 or later)
  • Android SDK 25, Build-Tools 25.0.2, Platform-Tools 25.x.x or later
  • A device running Android 4.1 or later with a camera and microphone
  • Internet connection

Prerequisites

Here are a few prerequisites that must be met before you can begin developing using ZEGOCLOUD.

Now let's begin coding!

Features overview

This will be a simple app that can do the following:

2 participants will join in the room and watch a movie together. Viewer A and Viewer B.

I decided to play and stream the movie to the room from a second device to guarantee a synchronized watching experience. It'll be known as the movie streamer. We will call it the movie streamer.

Streaming delay may cause out-of-sync issues if the movie is played from one of the participants' devices. If the movie is streamed from a separate device, both participants will be subscribing to and playing the cloud-based movie stream, reducing the likelihood of an out-of-sync issue.

While watching the movie, participants can video chat and text chat.

To keep things simple, I limited the number of people in the room to 3 for this project.

Movie streamer - Play a movie and have it streamed into the room

Step 1: Create a ZegoExpressEngine instance.

/// Define the ZegoExpressEngine object
ZegoExpressEngine engine;
/// Specify the AppID and AppSign for SDK authentication
/// AppID Format:123456789L
long appID = ; 
/// AppSign Format:"0123456789012345678901234567890123456789012345678901234567890123"
String appSign = "";
/// Create a ZegoExpressEngine instance
engine = ZegoExpressEngine.createEngine(appID, appSign, true, ZegoScenario.GENERAL, getApplication(), null); 

Step 2: Set the engine to capture custom video.

ZegoCustomVideoCaptureConfig videoCaptureConfig = new ZegoCustomVideoCaptureConfig();
// Use RAW_DATA as video buffer data type
videoCaptureConfig.bufferType = ZegoVideoBufferType.RAW_DATA;  engine.enableCustomVideoCapture(true, videoCaptureConfig, ZegoPublishChannel.MAIN);

Step 3: To use custom video capture, create a callback handler and implement the callback functions.

// Set the engine itself as the callback handler object
engine.setCustomVideoCaptureHandler(new IZegoCustomVideoCaptureHandler() {    
     @Override     
     public void onStart(ZegoPublishChannel channel) {         
     // On receiving the onStart callback, start to capture video and send the captured video frame data to the ZegoExpressEngine.

        ...     
     }    
      @Override     
      public void onStop(ZegoPublishChannel channel) {         
      // On receiving the onStop callback, stop the video capture process.
        ...     
      }
  });

Step 4:  Join the room.

/// Create a user
ZegoUser user = new ZegoUser("userA"); 
/// Join a room
engine.loginRoom("room", user);

Step 5: Create a video event handler for ZegoMediaPlayer. By configuring this handler, you may get video frame data from the movie being played via the callback onVideoFrame.

mZegoMediaPlayer.setVideoHandler(
    new IZegoMediaPlayerVideoHandler() {
        @Override
        public void onVideoFrame(ZegoMediaPlayer zegoMediaPlayer, ByteBuffer[] byteBuffers, int[] ints, ZegoVideoFrameParam zegoVideoFrameParam) { 
        if (RoomManager.getInstance().isCanSenRawData()) {
            int totalDataLength = byteBuffers[0].capacity();
            if (tempByteBuffer == null || tempByteBuffer.capacity() != totalDataLength) {
                tempByteBuffer = ByteBuffer.allocateDirect(byteBuffers[0].capacity()).put(byteBuffers[0]);
            } else {
                tempByteBuffer.clear();
                tempByteBuffer.put(byteBuffers[0]);
            }
            ZegoSDKManager.getInstance().getStreamService().sendCustomVideoCaptureRawData(tempByteBuffer, tempByteBuffer.capacity(), zegoVideoFrameParam);
            }
        }
    }, ZegoVideoFrameFormat.RGBA32);

Step 6: Start publishing to the stream. Start playing the movie from the supplied file location (local file directory or URL).

/// Start publishing the stream
engine.startPublishingStream("streamMovie");

mZegoMediaPlayer.loadResource(path, new IZegoMediaPlayerLoadResourceCallback() {
    @Override
    public void onLoadResourceCallback(int code) {
        if (code == 0) {
            mZegoMediaPlayer.start();
            if (callback != null) {
                callback.onLoadResourceCallback(code);
            }
        }
    }
});

Step 7: Stop publishing the stream when there are no other people in the room or when the person who is publishing the stream leaves the room. This will trigger the callback for stopping custom video capture.

ZegoSDKManager.getInstance().getDeviceService().setCustomVideoCaptureHandler(new IZegoVideoCaptureCallback() {
    @Override
    public void onStart(ZegoPublishChannel channel) {
        canSenRawData = true;
    }

    @Override
    public void onStop(ZegoPublishChannel channel) {
        canSenRawData = false;
    }
});

Movie viewer - subscribe to the movie stream to watch movies together, as well as video and text chat

To make the "watch together" feature work, we'll have to do the following:

  • The viewers subscribe to the video stream of the currently playing movie so that they may watch it together.
  • Both viewers can control the movie's playback. For instance, either of them can pause and restart playing.
  • Publish/subscribe to a stream and use the camera and microphone to video chat while watching a movie.
  • Real-time texting in the room.
High-level logic for movie-playing:

The movie streamer will first set up a room, and the viewers must join it (by using the same Room ID when using the loginRoom function).

If viewers try to join a room that doesn't exist or has no movie streamer, they'll see Room doesn't exist.

The room login will fail if the given room has surpassed its maximum capacity, and the participants will be notified.

Call setRoomExtraInfo() to send a notice to the movie streamer when a viewer presses the Start Movie button. The movie streamer will perform the logic to start playing the movie and streaming the movie to the room once it receives such notice via the onRoomExtraInfoUpdate() callback.

Both viewers will then receive the movie stream and watch it on their own devices.

/// start playing stream
engine.startPlayingStream("stream1", new ZegoCanvas(play_view));

The function setRoomExtraInfo(String roomID,String key,String value,null) may be used by both viewers to control the movie playing (Play or Pause).

The following table provides key-value arguments you may supply to setRoomExtraInfo to deliver different notifications:

keyvalueroomInfo0: movie being loaded...
1: movie playing
2: movie on pause
3: room has been closed

High-level logic for video chat:
  • After entering the room, viewer A (or B) can begin publishing video from the camera with a unique Stream ID and begin the local preview.
  • When another viewer joins the room and begins publishing video to the room, the ZEGO Express SDK will issue an event notice. Viewer A (or B) can then begin playing the video of the other viewer by inputting the Stream ID obtained from the callback message.
  • Both viewers may control their camera (front/rear, on/off) and microphone (mute/unmute).

/// Switch between the front/rear camera
expressEngine.useFrontCamera(front);

/// Turn on/off the camera
expressEngine.enableCamera(enable);

/// Mute or unmute the microphone
expressEngine.muteMicrophone(!enable);
High-level logic for text chat:
  • Both viewers in the room can send and receive text messages in real time.
  • To send a Broadcast Message (no longer than 1024 bytes) to other participants in the room, use the sendBroadcastMessage function.
/// Send broadcast messages
engine.sendBroadcastMessage(roomID, msg, new IZegoIMSendBroadcastMessageCallback() {
   @Override     
   public void onIMSendBroadcastMessageResult(int errorCode, long messageID) {   
    /// Returned result of sending broadcast messages       
   }
 });
  • Implement the onIMRecvBroadcastMessage callback function specified in IZegoEventHandler to listen for and handle Broadcast Messages sent by other participants. This callback returns message data such as message content, message ID, time message was delivered, and message sender.
  /// reveice message
public void onIMRecvBroadcastMessage(String roomID, ArrayList<ZegoBroadcastMessageInfo> messageList){          
}

How the final app looks like

The movie streamer view

Viewer view

You may download the demo app and try it yourself:

Download Demo & Source Code →

Demo instructions:
  1. Start the movie streamer, choose a movie, then configure the Room ID.
  2. Start the viewer app and enter the same Room ID.

Conclusion

I hope that after reading this article, you'll see that making an app for watching movies together is not that hard at all. Ready to create your own app?

More Reading

All Live Streaming Features in One Article

Tags

ZEGOCLOUD

Building stable and high-quality cloud streaming services for real-time audio and video communications.