package net.spacen.xxh_video; import static com.tencent.live2.V2TXLiveCode.V2TXLIVE_ERROR_INVALID_PARAMETER; import static com.tencent.live2.V2TXLiveCode.V2TXLIVE_OK; import androidx.appcompat.app.AppCompatActivity; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.AnimationDrawable; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.SurfaceView; import android.view.View; import android.view.WindowManager; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import android.widget.VideoView; import com.tencent.live2.V2TXLiveDef; import com.tencent.live2.V2TXLivePlayer; import com.tencent.live2.V2TXLivePlayerObserver; import com.tencent.live2.impl.V2TXLivePlayerImpl; import com.tencent.rtmp.TXLiveBase; import com.tencent.rtmp.TXLiveConstants; import com.tencent.rtmp.TXLivePlayer; import com.tencent.rtmp.ui.TXCloudVideoView; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import okhttp3.OkHttpClient; import tv.danmaku.ijk.media.player.IMediaPlayer; import tv.danmaku.ijk.media.player.IjkMediaPlayer; public class MainActivity extends AppCompatActivity implements View.OnClickListener { public final String TAG = MainActivity.class.getSimpleName(); private Context mContext; private ImageView mImageLoading; //显示视频缓冲动画 private RelativeLayout mLayoutRoot; //视频暂停时更新背景 private LinearLayout mLayoutToolbar; //视频Tools private RelativeLayout mliveplayer_title; private ImageView mImageRoot; //背景icon private ImageButton mButtonPlay; //视频的播放控制按钮 private ImageButton mButtonRenderRotation; //调整视频播放方向:横屏、竖屏 private ImageButton mButtonRenderMode; //调整视频渲染模式:全屏、自适应 private ImageButton mButtonCacheStrategy; //设置视频的缓存策略 private ImageView mImageCacheStrategyShadow; private ImageButton mImageLogInfo; //private RadioSelectView mLayoutCacheStrategy; //显示所有缓存模式的View //private LogInfoWindow mLogInfoWindow; private int mLogClickCount = 0; private V2TXLivePlayer mLivePlayer; //直播拉流的视频播放器 private TXCloudVideoView mVideoView; private VideoView vv_view; private SurfaceView sv_view; private IjkMediaPlayer ijkMediaPlayer; private String mPlayURL = ""; private boolean mIsPlaying = false; private boolean mFetching = false; //是否正在获取视频源,测试专用 private OkHttpClient mOkHttpClient = null; //获取超低时延视频源直播地址 private int mCacheStrategy = Constants.CACHE_STRATEGY_AUTO; //Player缓存策略 private int mActivityPlayType = Constants.ACTIVITY_TYPE_LIVE_PLAY; //播放类型 private V2TXLiveDef.V2TXLiveFillMode mRenderMode = V2TXLiveDef.V2TXLiveFillMode.V2TXLiveFillModeFit; //Player 当前渲染模式 private V2TXLiveDef.V2TXLiveRotation mRenderRotation = V2TXLiveDef.V2TXLiveRotation.V2TXLiveRotation0; //Player 当前渲染角度 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); MyMqttService.setCLIENTID(getAndroidID()); MyMqttService.startService(this); //开启服务 //timer.schedule(task,0,10000); String licenceURL = "https://license.vod2.myqcloud.com/license/v2/1304883579_1/v_cube.license"; // 获取到的 licence url String licenceKey = "cd83b2d9f0570e9ab4b5059a3cf5ba36"; // 获取到的 licence key TXLiveBase.getInstance().setLicence(this, licenceURL, licenceKey); EventBus.getDefault().register(this); mContext = this; TextView t1 = (TextView) findViewById(R.id.liveplayer_title_textview); t1.setText(getAndroidID()); Toast.makeText(this, getAndroidID() + " 哈哈,我成功启动了!", Toast.LENGTH_LONG).show(); Log.e("AutoRun","哈哈,我成功启动了!"); mPlayURL = "rtmp://v.dl8.tv/show/mini"; //mPlayerView 即 step1 中添加的界面 view mVideoView = (TXCloudVideoView) findViewById(R.id.video_view); vv_view = (VideoView) findViewById(R.id.vv_view); vv_view.setVisibility(View.GONE); initialize(); } @Override public void onClick(View view) { showToolbox(); } private void hideToolbox() { mLayoutToolbar.setVisibility(View.GONE); mliveplayer_title.setVisibility(View.GONE); } private void showToolbox() { mLayoutToolbar.setVisibility(View.VISIBLE); mliveplayer_title.setVisibility(View.VISIBLE); mLayoutToolbar.postDelayed(new Runnable() { @Override public void run() { hideToolbox(); }},10000); } private void initialize() { mLayoutRoot = (RelativeLayout) findViewById(R.id.liveplayer_rl_root); mliveplayer_title = (RelativeLayout) findViewById(R.id.liveplayer_title); mImageRoot = (ImageView) findViewById(R.id.liveplayer_iv_root); mLayoutToolbar = (LinearLayout) findViewById(R.id.liveplayer_ll_menu_layout); initPlayView(); initPlayButton(); initRenderRotationButton(); initRenderModeButton(); initCacheStrategyButton(); //initNavigationBack(); //initRTMPURL(); showToolbox(); // 初始化完成之后自动播放 startPlay(); } private void initPlayView() { mVideoView = (TXCloudVideoView) findViewById(R.id.video_view); mVideoView.setLogMargin(12, 12, 110, 60); mVideoView.showLog(false); mVideoView.setOnClickListener(this); vv_view.setOnClickListener(this); mLivePlayer = new V2TXLivePlayerImpl(mContext); mImageLoading = (ImageView) findViewById(R.id.liveplayer_iv_loading); } private void initCacheStrategyButton() { //mLayoutCacheStrategy = (RadioSelectView) findViewById(R.id.liveplayer_rsv_cache_strategy); mImageCacheStrategyShadow = (ImageView) findViewById(R.id.liveplayer_btn_cache_strategy_shadow); mButtonCacheStrategy = (ImageButton) findViewById(R.id.liveplayer_btn_cache_strategy); mButtonCacheStrategy.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(mContext, CameraPushEntranceActivity.class); /* intent.putExtra(Constants.INTENT_URL_PUSH, pushURL); intent.putExtra(Constants.INTENT_URL_PLAY_RTMP, rtmpPlayURL); intent.putExtra(Constants.INTENT_URL_PLAY_FLV, flvPlayURL); intent.putExtra(Constants.INTENT_URL_PLAY_HLS, hlsPlayURL); intent.putExtra(Constants.INTENT_URL_PLAY_ACC, realtimePlayURL); */ startActivity(intent); } }); } private void startPlay() { String playURL = mPlayURL; int code = checkPlayURL(playURL); if (code != Constants.PLAY_STATUS_SUCCESS) { mIsPlaying = false; } else { mLivePlayer.setRenderView(mVideoView); mLivePlayer.setObserver(new MyPlayerObserver()); mLivePlayer.setRenderRotation(mRenderRotation); mLivePlayer.setRenderFillMode(mRenderMode); mLivePlayer.setCacheParams(1.0f, 5.0f); /** * result返回值: * 0 V2TXLIVE_OK; -2 V2TXLIVE_ERROR_INVALID_PARAMETER; -3 V2TXLIVE_ERROR_REFUSED; */ code = mLivePlayer.startPlay(playURL); mIsPlaying = code == 0; Log.d("video render", "timetrack start play"); } //处理UI相关操作 onPlayStart(code); } @Override public void onBackPressed() { stopPlay(); super.onBackPressed(); } @Override public void onDestroy() { super.onDestroy(); destroy(); } private void startLoadingAnimation() { if (mImageLoading != null) { mImageLoading.setVisibility(View.VISIBLE); ((AnimationDrawable) mImageLoading.getDrawable()).start(); } } private void stopLoadingAnimation() { if (mImageLoading != null) { mImageLoading.setVisibility(View.GONE); ((AnimationDrawable) mImageLoading.getDrawable()).stop(); } } private void stopPlay() { if (!mIsPlaying) { return; } if (mLivePlayer != null) { mLivePlayer.setObserver(null); mLivePlayer.stopPlay(); } mIsPlaying = false; //处理UI相关操作 onPlayStop(); } private void destroy() { if (mOkHttpClient != null) { mOkHttpClient.dispatcher().cancelAll(); } if (mLivePlayer != null) { mLivePlayer.stopPlay(); mLivePlayer = null; } if (mVideoView != null) { mVideoView.onDestroy(); mVideoView = null; } } public void onPlayStop() { mButtonPlay.setBackgroundResource(R.drawable.liveplayer_play_start_btn); mLayoutRoot.setBackgroundResource(R.drawable.liveplayer_content_bg); mImageRoot.setVisibility(View.VISIBLE); // mLogInfoWindow.clear(); stopLoadingAnimation(); } private class MyPlayerObserver extends V2TXLivePlayerObserver { @Override public void onWarning(V2TXLivePlayer player, int code, String msg, Bundle extraInfo) { Log.w(TAG, "[Player] onWarning: player-" + player + " code-" + code + " msg-" + msg + " info-" + extraInfo); } @Override public void onError(V2TXLivePlayer player, int code, String msg, Bundle extraInfo) { Log.e(TAG, "[Player] onError: player-" + player + " code-" + code + " msg-" + msg + " info-" + extraInfo); } @Override public void onSnapshotComplete(V2TXLivePlayer v2TXLivePlayer, Bitmap bitmap) { } @Override public void onVideoPlayStatusUpdate(V2TXLivePlayer player, V2TXLiveDef.V2TXLivePlayStatus status, V2TXLiveDef.V2TXLiveStatusChangeReason reason, Bundle bundle) { Log.i(TAG, "[Player] onVideoPlayStatusUpdate: player-" + player + ", status-" + status + ", reason-" + reason); switch (status) { case V2TXLivePlayStatusLoading: //startLoadingAnimation(); break; case V2TXLivePlayStatusPlaying: //stopLoadingAnimation(); Bundle params = new Bundle(); params.putString(TXLiveConstants.EVT_DESCRIPTION, mContext.getResources().getString(R.string.liveplayer_warning_checkout_res_url)); //mLogInfoWindow.setLogText(null, params, LogInfoWindow.CHECK_RTMP_URL_OK); break; case V2TXLivePlayStatusStopped: if (reason == V2TXLiveDef.V2TXLiveStatusChangeReason.V2TXLiveStatusChangeReasonRemoteOffline) { stopPlay(); } default: break; } } @Override public void onAudioPlayStatusUpdate(V2TXLivePlayer player, V2TXLiveDef.V2TXLivePlayStatus status, V2TXLiveDef.V2TXLiveStatusChangeReason reason, Bundle bundle) { Log.i(TAG, "[Player] onAudioPlayStatusUpdate: player-" + player + ", status-" + status + ", reason-" + reason); switch (status) { case V2TXLivePlayStatusLoading: //startLoadingAnimation(); break; case V2TXLivePlayStatusPlaying: //stopLoadingAnimation(); break; case V2TXLivePlayStatusStopped: if (reason == V2TXLiveDef.V2TXLiveStatusChangeReason.V2TXLiveStatusChangeReasonRemoteOffline) { stopPlay(); } default: break; } } @Override public void onPlayoutVolumeUpdate(V2TXLivePlayer player, int volume) { // Log.i(TAG, "onPlayoutVolumeUpdate: player-" + player + ", volume-" + volume); } @Override public void onStatisticsUpdate(V2TXLivePlayer player, V2TXLiveDef.V2TXLivePlayerStatistics statistics) { Bundle netStatus = new Bundle(); netStatus.putInt(TXLiveConstants.NET_STATUS_VIDEO_WIDTH, statistics.width); netStatus.putInt(TXLiveConstants.NET_STATUS_VIDEO_HEIGHT, statistics.height); int appCpu = statistics.appCpu / 10; int totalCpu = statistics.systemCpu / 10; String strCpu = appCpu + "/" + totalCpu + "%"; netStatus.putCharSequence(TXLiveConstants.NET_STATUS_CPU_USAGE, strCpu); netStatus.putInt(TXLiveConstants.NET_STATUS_NET_SPEED, statistics.videoBitrate + statistics.audioBitrate); netStatus.putInt(TXLiveConstants.NET_STATUS_AUDIO_BITRATE, statistics.audioBitrate); netStatus.putInt(TXLiveConstants.NET_STATUS_VIDEO_BITRATE, statistics.videoBitrate); netStatus.putInt(TXLiveConstants.NET_STATUS_VIDEO_FPS, statistics.fps); netStatus.putInt(TXLiveConstants.NET_STATUS_AUDIO_CACHE, 0); netStatus.putInt(TXLiveConstants.NET_STATUS_VIDEO_CACHE, 0); netStatus.putInt(TXLiveConstants.NET_STATUS_V_SUM_CACHE_SIZE, 0); netStatus.putInt(TXLiveConstants.NET_STATUS_V_DEC_CACHE_SIZE, 0); netStatus.putString(TXLiveConstants.NET_STATUS_AUDIO_INFO, ""); Log.d(TAG, "Current status, CPU:" + netStatus.getString(TXLiveConstants.NET_STATUS_CPU_USAGE) + ", RES:" + netStatus.getInt(TXLiveConstants.NET_STATUS_VIDEO_WIDTH) + "*" + netStatus.getInt(TXLiveConstants.NET_STATUS_VIDEO_HEIGHT) + ", SPD:" + netStatus.getInt(TXLiveConstants.NET_STATUS_NET_SPEED) + "Kbps" + ", FPS:" + netStatus.getInt(TXLiveConstants.NET_STATUS_VIDEO_FPS) + ", ARA:" + netStatus.getInt(TXLiveConstants.NET_STATUS_AUDIO_BITRATE) + "Kbps" + ", VRA:" + netStatus.getInt(TXLiveConstants.NET_STATUS_VIDEO_BITRATE) + "Kbps"); //mLogInfoWindow.setLogText(netStatus, null, 0); } } private int checkPlayURL(final String playURL) { if (TextUtils.isEmpty(playURL)) { return Constants.PLAY_STATUS_EMPTY_URL; } if (!playURL.startsWith(Constants.URL_PREFIX_HTTP) && !playURL.startsWith(Constants.URL_PREFIX_HTTPS) && !playURL.startsWith(Constants.URL_PREFIX_RTMP) && !playURL.startsWith("/")) { return Constants.PLAY_STATUS_INVALID_URL; } boolean isLiveRTMP = playURL.startsWith(Constants.URL_PREFIX_RTMP); boolean isLiveFLV = (playURL.startsWith(Constants.URL_PREFIX_HTTP) || playURL.startsWith(Constants.URL_PREFIX_HTTPS)) && playURL.contains(Constants.URL_SUFFIX_FLV); if (mActivityPlayType == Constants.ACTIVITY_TYPE_LIVE_PLAY) { if (isLiveRTMP) { return Constants.PLAY_STATUS_SUCCESS; } if (isLiveFLV) { return Constants.PLAY_STATUS_SUCCESS; } return Constants.PLAY_STATUS_INVALID_URL; } if (mActivityPlayType == Constants.ACTIVITY_TYPE_REALTIME_PLAY) { if (!isLiveRTMP) { return Constants.PLAY_STATUS_INVALID_RTMP_URL; } if (!playURL.contains(Constants.URL_TX_SECRET)) { return Constants.PLAY_STATUS_INVALID_SECRET_RTMP_URL; } return Constants.PLAY_STATUS_SUCCESS; } return Constants.PLAY_STATUS_INVALID_URL; } private void togglePlay() { Log.d(TAG, "togglePlay: mIsPlaying:" + mIsPlaying + ", mCurrentPlayType:" + mActivityPlayType); if (mIsPlaying) { stopPlay(); } else { startPlay(); } } public void onPlayStart(int code) { /* switch (code) { case V2TXLIVE_OK: startLoadingAnimation(); break; case V2TXLIVE_ERROR_INVALID_PARAMETER: Toast.makeText(mContext, R.string.liveplayer_warning_res_url_invalid, Toast.LENGTH_SHORT).show(); break; default: break; } if (code != V2TXLIVE_OK) { mButtonPlay.setBackgroundResource(R.drawable.liveplayer_play_start_btn); mLayoutRoot.setBackgroundResource(R.drawable.liveplayer_content_bg); mImageRoot.setVisibility(View.VISIBLE); Bundle params = new Bundle(); params.putString(TXLiveConstants.EVT_DESCRIPTION, mContext.getResources().getString(R.string.liveplayer_warning_checkout_res_url)); mLogInfoWindow.setLogText(null, params, LogInfoWindow.CHECK_RTMP_URL_FAIL); } else { mButtonPlay.setBackgroundResource(R.drawable.liveplayer_play_pause_btn); mLayoutRoot.setBackgroundColor(getResources().getColor(R.color.liveplayer_black)); mImageRoot.setVisibility(View.GONE); Bundle params = new Bundle(); params.putString(TXLiveConstants.EVT_DESCRIPTION, mContext.getResources().getString(R.string.liveplayer_warning_checkout_res_url)); mLogInfoWindow.setLogText(null, params, LogInfoWindow.CHECK_RTMP_URL_OK); } */ } private void initPlayButton() { mButtonPlay = (ImageButton) findViewById(R.id.liveplayer_btn_play); mButtonPlay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { togglePlay(); } }); } private void initRenderRotationButton() { mButtonRenderRotation = (ImageButton) findViewById(R.id.liveplayer_btn_render_rotate_landscape); mButtonRenderRotation.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { V2TXLiveDef.V2TXLiveRotation renderRotation = getRenderRotation(); if (renderRotation == V2TXLiveDef.V2TXLiveRotation.V2TXLiveRotation0) { mButtonRenderRotation.setBackgroundResource(R.drawable.liveplayer_render_rotate_portrait); renderRotation = V2TXLiveDef.V2TXLiveRotation.V2TXLiveRotation270; } else if (renderRotation == V2TXLiveDef.V2TXLiveRotation.V2TXLiveRotation270) { mButtonRenderRotation.setBackgroundResource(R.drawable.liveplayer_render_rotate_landscape); renderRotation = V2TXLiveDef.V2TXLiveRotation.V2TXLiveRotation0; } setRenderRotation(renderRotation); } }); } private void setRenderMode(V2TXLiveDef.V2TXLiveFillMode renderMode) { mRenderMode = renderMode; mLivePlayer.setRenderFillMode(renderMode); } private V2TXLiveDef.V2TXLiveFillMode getRenderMode() { return mRenderMode; } private void setRenderRotation(V2TXLiveDef.V2TXLiveRotation renderRotation) { mRenderRotation = renderRotation; mLivePlayer.setRenderRotation(renderRotation); } private V2TXLiveDef.V2TXLiveRotation getRenderRotation() { return mRenderRotation; } private void initRenderModeButton() { mButtonRenderMode = (ImageButton) findViewById(R.id.liveplayer_btn_render_mode_fill); mButtonRenderMode.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { V2TXLiveDef.V2TXLiveFillMode renderMode = getRenderMode(); if (getRenderMode() == V2TXLiveDef.V2TXLiveFillMode.V2TXLiveFillModeFill) { mButtonRenderMode.setBackgroundResource(R.drawable.liveplayer_render_mode_fill); renderMode = V2TXLiveDef.V2TXLiveFillMode.V2TXLiveFillModeFit; } else if (getRenderMode() == V2TXLiveDef.V2TXLiveFillMode.V2TXLiveFillModeFit) { mButtonRenderMode.setBackgroundResource(R.drawable.liveplayer_adjust_mode_btn); renderMode = V2TXLiveDef.V2TXLiveFillMode.V2TXLiveFillModeFill; } setRenderMode(renderMode); } }); } private String getAndroidID() { return Settings.Secure.getString( getContentResolver(), Settings.Secure.ANDROID_ID); } @Subscribe(threadMode = ThreadMode.MAIN) public void onGetMessage(MessageWrap message) { // getBinding().tvMessage.setText(message.message); // Log.i(TAG, "收到消息: " + new String(message.message)); // Toast.makeText(getApplicationContext(), "EventBus: " + new String(message.message), Toast.LENGTH_LONG).show(); String url = new String(message.message); if (url.substring(url.length()-4).equals("m3u8")){ mLivePlayer.stopPlay(); mVideoView.setVisibility(View.GONE); vv_view.setVisibility(View.VISIBLE); vv_view.setVideoPath(url); vv_view.start(); } else { vv_view.stopPlayback(); vv_view.setVisibility(View.GONE); mVideoView.setVisibility(View.VISIBLE); mLivePlayer.startPlay(url); } } }