Johan Vorster
Johan Vorster

Reputation: 473

Can't play mp4 on Android from Azure Blob Storage

I am creating a mobile application that does the following

The sequence has been perfectly implemented on iOS.

On Android however, I can record the video, save the video, upload the video, but cannot stream (progressive download) the file from Azure using VideoView and MediaController.

I get the "Can't play this video"

The video I uploaded from the Android app does work on iOS and HTML5 and pretty much any other media player.

If I choose to play the *.mp4 I saved locally (before uploading the *.mp4) through VideoView, it works fine. So at this stage, before uploading to Azure, the video seems in a working condition.

Another test I did, was to upload Big Buck Bunny, through Azure Storage Explorer, and that seems to work perfectly.

So I suspect I am might be missing a header when I upload the file to Azure or incorrect encoding for streaming.

Here is my code, nothing extraordinary:

MediaRecorder Settings to display and record the video:

mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setOutputFile(getVideoFile(activity).getAbsolutePath());
mediaRecorder.setVideoEncodingBitRate(1000000);
mediaRecorder.setVideoFrameRate(5);
mediaRecorder.setVideoSize(videoSize.getWidth(), videoSize.getHeight());
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

Upload the file by using CloudBlockBlob:

StorageCredentials credentials = new StorageCredentialsSharedAccessSignature(sasQueryString);
URI containerUri = new URI(blobUri);
CloudBlockBlob blob = new CloudBlockBlob(URI.create(blobUri), credentials);
blob.getProperties().setContentType("video/mp4");
blob.uploadFromFile(imageUri);

Trying to play the uploaded file:

videoView = (VideoView) findViewById(R.id.videoView);
MediaController mediaController = new MediaController(this);
videoView.setVideoURI(Uri.parse("http://xox.blob.core.windows.net/container/movie.mp4"));
videoView.setMediaController(mediaController);
videoView.start();

At which point I get "Can't play this video"!

As I said to start off with, this uploaded file works seemingly on every other media player including iOS and HTML5. And if I play the locally saved version of the file on Android, it works.

But I can't play the file on Android from Azure after uploaded. Nor can I play the file created and uploaded by iOS created on Android.

Is it encoding the issue? Am I uploading the blob incorrectly? What makes Android's ViewVideo stricter on which video's it will play as oppose to other media players

Upvotes: 2

Views: 2006

Answers (4)

Oscar Sanchez
Oscar Sanchez

Reputation: 26

I was facing the same problem, so I created a method to create to get the video:

public static byte[] getVideo(String videoName) {
    try {
        // Get a reference to the blob
        CloudBlockBlob blob = container.getBlockBlobReference(videoName);

        // Check if the blob exists
        if (!blob.exists()) {
            System.out.println("Blob video does not exist: " + videoName);
            return null; // Return null if the blob does not exist
        }

        URI blobUri = blob.getUri();
        System.out.println("Azure Blob URL video: " + blobUri);

        // Create a ByteArrayOutputStream to store the video data
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        
        // Download the blob's content to the ByteArrayOutputStream
        blob.download(outputStream);

        // Close the ByteArrayOutputStream
        outputStream.close();

        // Return the video data as a byte array
        return outputStream.toByteArray();
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

Then in my Fragment:

byte[] videoData = azureManager.getVideo("azureVideoName");
try {
    // Create a temporary file to store the video
    File tempFile = File.createTempFile(videoName, ".mp4", getContext().getCacheDir());
    FileOutputStream fos = new FileOutputStream(tempFile);
    fos.write(videoData);
    fos.close();
    videoView.requestFocus();

    // Set the video URI to the local temporary file
    videoView.setVideoURI(Uri.fromFile(tempFile));

    // Start the video playback
    videoView.start();
} catch (IOException e) {
    e.printStackTrace();
}

Upvotes: 0

Ankit
Ankit

Reputation: 429

@Peter's answer should work. just instead of MediaPlayer.prepare() call MediaPlayer.prepareAsync() after setting Prepared listener.

And while recording in ios if you are simply changing extension of video from .mov to .mp4 then most of android device will not play it. also verify that in a MP4 container video stream should be encoded using H264 codec and audio with AAC codec.

Upvotes: 0

Yuri Korshev
Yuri Korshev

Reputation: 85

Try using this Library: https://github.com/brianwernick/ExoMedia

It encapsulate ExoPlayer api similar to VideoView's API.

Also, facing issue while trying to play recorder and converted with FFMPEG videos from Azure Blob Storage.

Upvotes: 1

Peter
Peter

Reputation: 27944

You probably calling the start() to early, start the video when the mediaplayer is ready to start playing: Reference MediaPlayer

videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  public void onPrepared(MediaPlayer mp) {
    videoView.start();
  }
});

Upvotes: 1

Related Questions