[Huawei Developers] John Wo:
Video is visual multimedia source that combines a sequence of images to form a moving picture. The video transmits a signal to a screen and processes the order in which the screen captures should be shown.

Videos usually have audio components that correspond with the pictures being shown on the screen.

Video was first developed for “Mechanical Television” systems which were quickly replaced by cathode ray tube (CRT) and eventually replaced by flat panel displays of several types.

Huawei Video Kit brings the wonderful experience to playback the high quality videos streaming from a third party cloud platform.

Huawei Video Kit supports the streaming media in 3GP,MP4 or TS formats and comply with HTTP/HTTPS, HLS or DASH.

Huawei Video Kit will also be supporting the video hosting and editing feature in coming versions.

Features

Video Kit provides smooth playback.

It provides secure and stable solution.

It leverages the anti-leeching experience so that bandwidth is not drained out.

It allows wide ranging playback controls.

Supports playback authentication.

Development Overview

Prerequisite

Must have a Huawei Developer Account

Must have Android Studio 3.0 or later

Must have a Huawei phone with HMS Core 5.0.0.300 or later

EMUI 3.0 or later

Software Requirements

Java SDK 1.7 or later

Android 5.0 or later

Preparation

Create an app or project in the Huawei AppGallery Connect.

Provide the SHA Key and App Package name of the project in App Information Section and enable the required API.

Create an Android project.

Note: Video Kit SDK can be directly called by devices, without connecting to AppGallery Connect and hence it is not mandatory to download and integrate the agconnect-services.json.

Integration

Add below to build.gradle (project)file, under buildscript/repositories and allprojects/repositories.

<p style="line-height: normal;">Maven {url 'http://developer.huawei.com/repo/'}</p>

Add below to build.gradle (app) file, under dependencies.

<p style="line-height: normal;">implementation "com.huawei.hms:videokit-player:1.0.1.300" </p>

Adding permissions

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.huawei.permission.SECURITY_DIAGNOSE" />

Development Process

A small trip application has been created to demonstrate the capabilities to Huawei Video Kit.

It lists all the amusement places to visit around with the use of GridView RecyclerView and card view.

To achieve it below classes are created.

Initializing WisePlayer

We have to implement a class that inherits Application and the onCreate() method has to call the initialization API WisePlayerFactory.initFactory().

public class VideoKitPlayApplication extends Application {
private static final String TAG = VideoKitPlayApplication.class.getSimpleName();
private static WisePlayerFactory wisePlayerFactory = null;
@Override
public void onCreate() {
super.onCreate();
initPlayer();
}
private void initPlayer() {
// DeviceId test is used in the demo.
WisePlayerFactoryOptions factoryOptions = new WisePlayerFactoryOptions.Builder().setDeviceId("xxx").build();
WisePlayerFactory.initFactory(this, factoryOptions, initFactoryCallback);
}
/**
* Player initialization callback
*/
private static InitFactoryCallback initFactoryCallback = new InitFactoryCallback() {
@Override
public void onSuccess(WisePlayerFactory wisePlayerFactory) {
LogUtil.i(TAG, "init player factory success");
setWisePlayerFactory(wisePlayerFactory);
}
@Override
public void onFailure(int errorCode, String reason) {
LogUtil.w(TAG, "init player factory failed :" + reason + ", errorCode is " + errorCode);
}
};
/**
* Get WisePlayer Factory
*
* @return WisePlayer Factory
*/
public static WisePlayerFactory getWisePlayerFactory() {
return wisePlayerFactory;
}
private static void setWisePlayerFactory(WisePlayerFactory wisePlayerFactory) {
VideoKitPlayApplication.wisePlayerFactory = wisePlayerFactory;
}
}

Creating instance of wise player

wisePlayer = VideoKitPlayApplication.getWisePlayerFactory().createWisePlayer();

WisePlayer layout

private void initView(View view) {
if (view != null) {
surfaceView = (SurfaceView) view.findViewById(R.id.surface_view);
textureView = (TextureView) view.findViewById(R.id.texture_view);
if (PlayControlUtil.isSurfaceView()) {
//SurfaceView display interface
SurfaceHolder surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(thois);
textureView.setVisibility(View.GONE);
surfaceView.setVisibility(View.VISIBLE);
} else {
//TextureView display interface
textureView.setSurfaceTextureListener(this);
textureView.setVisibility(View.VISIBLE);
surfaceView.setVisibility(View.GONE);
}
}

Register WisePlayer listeners

private void setPlayListener() {
if (wisePlayer != null) {
wisePlayer.setErrorListener(onWisePlayerListener);
wisePlayer.setEventListener(onWisePlayerListener);
wisePlayer.setResolutionUpdatedListener(onWisePlayerListener);
wisePlayer.setReadyListener(onWisePlayerListener);
wisePlayer.setLoadingListener(onWisePlayerListener);
wisePlayer.setPlayEndListener(onWisePlayerListener);
wisePlayer.setSeekEndListener(onWisePlayerListener);
}
}

Set playback parameters

player.setVideoType(PlayMode.PLAY_MODE_NORMAL);
player.setBookmark(10000);
player.setCycleMode(CycleMode.MODE_CYCLE);

Set URL for video

wisePlayer.setPlayUrl(new String[] {currentPlayData.getUrl()});

Set a view to display the video.

// SurfaceView listener callback
@Override
public void surfaceCreated(SurfaceHolder holder) {
wisePlayer.setView(surfaceView);
}
// TextureView listener callback
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
wisePlayer.setView(textureView);
// Call the resume API to bring WisePlayer to the foreground.
wisePlayer.resume(ResumeType.KEEP);
}

Prepare for the playback and start requesting data.

wisePlayer.ready();

Start the playback After success response

@Override
public void onReady(WisePlayer wisePlayer) {
player.start();
}

activity main.xml

Create a view for Recycler View.

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

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/player_recycler_view"
android:background="@drawable/images"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="0dp" />
</RelativeLayout>

select_play_view

Create card view for displaying the trip locations.

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

<androidx.cardview.widget.CardView
android:id="@+id/card_view"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="230dp"
android:layout_margin="5dp"
card_view:cardBackgroundColor="@color/cardcolour"
card_view:cardCornerRadius="10dp"
card_view:cardElevation="5dp"
card_view:cardUseCompatPadding="true">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
>

<ImageView
android:id="@+id/videoIcon"
android:tag="image_tag"
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_margin="5dp"
android:layout_weight="1"
android:src="@drawable/1"/>

<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_weight="2"
android:orientation="vertical"
>

<TextView
android:id="@+id/play_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:text=""
android:textColor="@color/colorTitle"
android:textAppearance="?android:attr/textAppearanceLarge"/>

<TextView
android:id="@+id/briefStory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="10dp"
android:textColor="@color/green"
android:textAppearance="?android:attr/textAppearanceSmall"/>
<TextView
android:id="@+id/play_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textColor="@color/select_play_text_color"
android:textSize="20sp"
android:visibility="gone"/>

<TextView
android:id="@+id/play_url"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:marqueeRepeatLimit="marquee_forever"
android:maxLines="2"
android:paddingTop="5dip"
android:singleLine="false"
android:textColor="@color/select_play_text_color"
android:textSize="14sp"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>

Data Adapter to hold the data for Recycler View

package com.huawei.video.kit.demo.adapter;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.huawei.video.kit.demo.R;
import com.huawei.video.kit.demo.contract.OnItemClickListener;
import com.huawei.video.kit.demo.entity.PlayEntity;
import com.huawei.video.kit.demo.utils.LogUtil;
import com.huawei.video.kit.demo.utils.StringUtil;
import com.squareup.picasso.Picasso;

/**
* Play recyclerView adapter
*/
public class SelectPlayDataAdapter extends RecyclerView.Adapter<SelectPlayDataAdapter.PlayViewHolder> {
private static final String TAG = "SelectPlayDataAdapter";

// Data sources list
private List<PlayEntity> playList;

// Context
private Context context;

// Click item listener
private OnItemClickListener onItemClickListener;

/**
* Constructor
*
* @param context Context
* @param onItemClickListener Listener
*/
public SelectPlayDataAdapter(Context context, OnItemClickListener onItemClickListener) {
this.context = context;
playList = new ArrayList<>();
this.onItemClickListener = onItemClickListener;
}

/**
* Set list data
*
* @param playList Play data
*/
public void setSelectPlayList(List<PlayEntity> playList) {
if (this.playList.size() > 0) {
this.playList.clear();
}
this.playList.addAll(playList);
notifyDataSetChanged();
}

@NonNull
@Override
public PlayViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.select_play_item, parent, false);
return new PlayViewHolder(view);
}

@Override
public void onBindViewHolder(PlayViewHolder holder, final int position) {
if (playList.size() > position && holder != null) {
PlayEntity playEntity = playList.get(position);
if (playEntity == null) {
LogUtil.i(TAG, "current item data is empty.");
return;
}
StringUtil.setTextValue(holder.playName, playEntity.getName());
//StringUtil.setTextValue(holder.releasedYear, playEntity.getYear());
StringUtil.setTextValue(holder.briefStory, playEntity.getStory());
StringUtil.setTextValue(holder.playUrl, playEntity.getUrl());
StringUtil.setTextValue(holder.playType, String.valueOf(playEntity.getUrlType()));
holder.itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(position);
}
});

Picasso.with(context).load(playEntity.getIcon()).into(holder.videoIcon);
}
}

@Override
public int getItemCount() {
return playList.size();
}

/**
* Show view holder
*/
static class PlayViewHolder extends RecyclerView.ViewHolder {

// The video name
private TextView playName;
private TextView briefStory;

// The video type
private TextView playType;

// The video url
private TextView playUrl;

private ImageView videoIcon

/**
* Constructor
*
* @param itemView Item view
*/
public PlayViewHolder(View itemView) {
super(itemView);
if (itemView != null) {
playName = itemView.findViewById(R.id.play_name);
briefStory = itemView.findViewById(R.id.briefStory);
playType = itemView.findViewById(R.id.play_type);
playUrl = itemView.findViewById(R.id.play_url);
videoIcon = itemView.findViewById(R.id.videoIcon);
}
}
}
}

HomePageView

This associated with the view of recycler view.

package com.huawei.video.kit.demo.view;
import java.util.List;
import android.content.Context;

import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;

import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.huawei.video.kit.demo.R;
import com.huawei.video.kit.demo.adapter.SelectPlayDataAdapter;
import com.huawei.video.kit.demo.contract.OnHomePageListener;
import com.huawei.video.kit.demo.entity.PlayEntity;
import com.huawei.video.kit.demo.utils.DialogUtil;

/**
* Home page view
*/
public class HomePageView {

int numberOfColumns = 2;
// Home page parent view
private View contentView;

// Context
private Context context;

// Play recyclerView
private RecyclerView playRecyclerView;

// Input play url
private EditText addressEt;

// Play button
private Button playBt;

// Play adapter
private SelectPlayDataAdapter selectPlayDataAdapter;

// Listener
private OnHomePageListener onHomePageListener;

/**
* Constructor
*
* @param context Context
* @param onHomePageListener Listener
*/
public HomePageView(Context context, OnHomePageListener onHomePageListener) {
this.context = context;
this.onHomePageListener = onHomePageListener;
initView();
}

/**
* Get parent view
*
* @return Parent view
*/
public View getContentView() {
return contentView;
}

/**
* Init view
*/
private void initView() {

contentView = LayoutInflater.from(context).inflate(R.layout.activity_main, null);

playRecyclerView = (RecyclerView) contentView.findViewById(R.id.player_recycler_view);
GridLayoutManager gridLayoutManager = new GridLayoutManager(context.getApplicationContext(),numberOfColumns);
playRecyclerView.setLayoutManager(gridLayoutManager);
playLoading = (ProgressBar) contentView.findViewById(R.id.play_loading);
addressEt = (EditText) contentView.findViewById(R.id.input_path_ed);
playBt = (Button) contentView.findViewById(R.id.main_play_btn);
playBt.setOnClickListener(onHomePageListener);
selectPlayDataAdapter = new SelectPlayDataAdapter(context, onHomePageListener);
// playRecyclerView.setLayoutManager(new LinearLayoutManager(context));
playRecyclerView.setAdapter(selectPlayDataAdapter);
playRecyclerView.setVisibility(View.GONE);
playLoading.setVisibility(View.VISIBLE);
}

/**
* Set the current data list
*
* @param playList Data list
*/
public void updateRecyclerView(List<PlayEntity> playList) {
selectPlayDataAdapter.setSelectPlayList(playList);
playLoading.setVisibility(View.GONE);
playRecyclerView.setVisibility(View.VISIBLE);
}

/**
* Get input text
*
* @return Text value
*/
public String getInputUrl() {
if (addressEt.getText() == null) {
return "";
} else {
return addressEt.getText().toString();
}
}
}

Results

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/834/235/2640091000001834235.20201009144029.83142770767602756543367092210826:50511021015810:2800:2E2DC0EB7DBB5F134D750ADCD32F4CD0821EF27A66741E5B7FB3E97A8B38A8A8.png"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/834/235/2640091000001834235.20201009144029.83142770767602756543367092210826:50511021015810:2800:2E2DC0EB7DBB5F134D750ADCD32F4CD0821EF27A66741E5B7FB3E97A8B38A8A8.png[/IMG]

[IMG="https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/834/235/2640091000001834235.20201009144304.38485304020539091111003956385860:50511021015810:2800:4267540EE0FC3DB5C744BF811EE0EDB9DB34BA4B86F6AAA34DBA9CE6108929AA.gif"]https://communityfile-dre.op.hicloud.com/FileServer/getFile/cmtybbs/001/834/235/2640091000001834235.20201009144304.38485304020539091111003956385860:50511021015810:2800:4267540EE0FC3DB5C744BF811EE0EDB9DB34BA4B86F6AAA34DBA9CE6108929AA.gif[/IMG]

Conclusion

We learnt a simple application which explains the power video kit apis and showcase how easy it to have the videos running in out applications.

References

https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides-V5/introduction-0000001050439577-V5