Implement the player (Open Source Code) and Android source code for playing below in Android
I. Preface:
Some time ago, I got an android TV box Remote Control Input APP: TVRemoteIME, which implements remote cross-screen input, remote control, and application management.
Recently, it was found that in addition to buying APP members, the number of third-party apps that can directly play movies for free is getting fewer and fewer, either the update is not timely, the number of movie resources is very small, or there are a large number of advertisements. It is very easy to find a movie to play on the computer. Because of the large number of movie resource websites set up by individuals on the network or BT downloads, I thought of adding the player function on my TVRemoteIME, in this way, you can directly enter a playback resource address on the control terminal (mobile phone, computer, or PAD) or upload a movie resource file (video file or seed file) to play the video in the TV box.
Get started with the idea ......
II. Implementation of the download function
Movie resource files on the current network can be played only after they are downloaded. Many formats are thunder, ed2k, and seed files (magnetic chains. To enable the download and playback functions, you must first solve the problem of resource download. The initial idea was to download the seed file, that is, to implement the BT protocol. I have known MonoTorrent as an open-source project before, so I think it should not be a problem to implement BT download in Android. As I first entered the android portal, I tried to find out if there were any available "Wheels". While searching on GitHub, I accidentally found this MiniThunder project, it has completely implemented the file download function of the seed, ed2k, thunder and other protocols, and also supports the video download and play function! It's exactly what I want!
Sample Code:
// Initialize XLTaskHelper. init (context); // Add a Network File Download task (http: //, thunder: //, ed2k: //, ftp: //, and other protocols) XLTaskHelper. instance (). addThunderTask (url, localSavePath, null); // Add the download task XLTaskHelper for the seed file. instance (). addtorshorttask (filename, localSavePath, indexs); // obtain the local playback address of the video file (the task is required to be downloaded) XLTaskHelper. instance (). getLoclUrl (this. localSavePath + item. getName ());
Note: The MiniThunder project uses the functions implemented by the thunder database. The specific license is unknown for the time being. We recommend that you do not use it for commercial purposes. During the test, it is found that the magnetic link has a download task in the project library, but it cannot be downloaded. The download interface has been disabled by thunder.
Iii. Player implementation
There are too many open-source and non-open-source projects for Android players, such as Android native VideoView or Google ExoPlayer projects, domestic ijkplayer on site B, Baidu Player SDK, thunder's Aplayer player engine and so on. The native VideoView supports too few video formats, so it is the first to stop using it. Finally, I chose ijkplayer for site B because it is fully open-source and supports many video protocols. You can find a lot of ijkplayer sample project code on Github. Using the existing "Wheel" directly saves you the trouble of designing the UI, so you can find an AFAP Player project, the sample player of Baidu and ijkplayer has been completed, and the interface is very concise and suitable for my requirements. However, in order to realize the playback list function, I have added some functions based on AFAP Player. Because the Player is playing on the TV box, it cannot be controlled by the touch, therefore, remote control compatibility is required.
We mainly implement the following functions for remote control operations:
1. Press the left and right keys to implement the fast playback and fast forward functions.
2. Press the up/down key to select a playlist (for example, if there are multiple video sources, for example, a large number of video files may be contained in the seed resource file)
3. Press the OK key to enable and disable playback.
4. Press the return key to exit the player.
The function implementation code is as follows: (the code is excerpted from the XLVideoPlayActivity. java file of TVRemoteIME)
private boolean changeProgressByKey = false; private int oldProgressValue = -1; private int newProgressValue = -1; @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: if(changeProgressByKey){ changeProgressByKey = false; oldProgressValue = -1; endGesture(); } break; } return super.onKeyUp(keyCode, event); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode){ case KeyEvent.KEYCODE_ESCAPE: case KeyEvent.KEYCODE_BACK: if(playListView.isShown()) { show(defaultTimeout); return true; } break; case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: if(!changeProgressByKey)changeProgressByKey = true; if(oldProgressValue == -1){ oldProgressValue = 0; newProgressValue = oldProgressValue; } newProgressValue += keyCode == KeyEvent.KEYCODE_DPAD_LEFT ? -1 : 1; Log.d(TAG, "newProgressValue = " + newProgressValue); if(newProgressValue < (0 - seekBar.getMax()))newProgressValue = (0 - seekBar.getMax()); if(newProgressValue > seekBar.getMax())newProgressValue = seekBar.getMax(); float deltaP = oldProgressValue - newProgressValue; onProgressSlide(-deltaP / seekBar.getMax()); return true; case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_UP: if(playListView.isShown()){ View view = playListView.getLayoutManager().getFocusedChild(); if(view != null){ View nextView = playListView.getLayoutManager().onInterceptFocusSearch(view, keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? View.FOCUS_DOWN : View.FOCUS_UP); if(nextView != null)nextView.requestFocus(); }else { playListView.requestFocus(keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? View.FOCUS_DOWN : View.FOCUS_UP); } return true; }else if(xlDownloadManager.taskInstance().getPlayList().size() > 1){ playListView.setVisibility(View.VISIBLE); return true; } break; case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_DPAD_CENTER: doPauseResume(); show(defaultTimeout); return true; } return super.onKeyDown(keyCode, event); }
Note: Fast forward or fast forward may skip a playback period, that is, during the remote control operation, the left and right keys remain unchanged. Therefore, only the progress value is recorded when the left and right keys are pressed in the code, and the fast return/fast forward function is executed when the left and right keys are on the event.
IV. Implementation of edge and bottom play
The download function and the player have two "Wheels". To implement the play-and-play function, you only need to assemble the two "Wheels. Here I wrote a DownloadTask class to integrate this function. For the complete code of this class, see the project code.
1. You need to receive a video source address parameter before starting the player:
mVideoPath = getIntent().getStringExtra("videoPath");
This video source address supports live video source addresses (http: //, rtmp: //, mms: //), local videos, and seed files (. torrent), network video source (thunder: //, ed2k ://).
2. Pass the video source address to the DownloadTask class for processing.
xlDownloadManager.taskInstance().setUrl(mVideoPath);
DownloadTask analyzes the video format of the video source address, and analyzes whether it is a live video source, a local file, or a network video file. If it is a seed file, it also analyzes the seed file, only the video files in the seed files are processed.
Public void setUrl (String url) {this. url = url; // Delete the old task and file this. stopTask (); this. playList. clear (); this. mIsLiveMedia = FileUtils. isLiveMedia (this. url); this. isNetworkDownloadTask =! This. mIsLiveMedia & FileUtils. isNetworkDownloadTask (this. url); this. name = this. mIsLiveMedia? FileUtils. getWebMediaFileName (this. url): this. isNetworkDownloadTask? XLTaskHelper. instance (). getFileName (this. url): FileUtils. getFileName (this. url); this. localSavePath = (new File (getBaseDir (), FileUtils. getFileNameWithoutExt (this. name )). toString () + "/"; this. isLocalMedia =! This. mIsLiveMedia &&! This. isNetworkDownloadTask & FileUtils. isMediaFile (this. name); this. torrentInfo = null; this. torrentMediaIndexs = null; this. torrentUnmediaIndexs = null; this. currentPlayMediaIndex = 0; if (this. isLocalMedia) {playList. add (new PlayListItem (this. name, 0, new File (this. getUrl ()). length ();} else if (this. mIsLiveMedia | this. isNetworkDownloadTask) {playList. add (new PlayListItem (this. name, 0, 0L);} else if (". torrent ". equals (FileUtils. getFileExt (this. name) {this. torrentInfo = XLTaskHelper. instance (). getTorrentInfo (this. url); this. initTorrentIndexs ();}}
3. Start the download task
xlDownloadManager.taskInstance().startTask()
When DownloadTask starts a task, the corresponding processing will be performed according to the video source format. If it is a live stream source and a local video file, it will not be downloaded, if it is a seed file or a network video file, it will call XLTaskHelper to add a download task.
Public boolean startTask () {if (TextUtils. isEmpty (this. url) | this. taskId! = 0L) {return false;} if (this. isNetworkDownloadTask) {if (this. url. toLowerCase (). startsWith ("magnet :? ") {Log. e (TAG, "download and playback of magnet links not supported currently"); return false;} else {taskId = XLTaskHelper. instance (). addThunderTask (this. url, localSavePath, null) ;}} else if (this. torrentInfo! = Null) {if (this. currentPlayMediaIndex! =-1) {try {taskId = XLTaskHelper. instance (). addTorrentTask (this. url, localSavePath, this. gettorincludeselectedindexs ();} catch (Exception e) {}} else {taskId = this. isLocalMedia | this. mIsLiveMedia? -9999L: 0L;} Log. d (TAG, "startTask (" + this. url + "), taskId =" + taskId); return taskId! = 0L ;}
4. start downloading and playing
mVideoView.setVideoPath(xlDownloadManager.taskInstance().getPlayUrl());
When DownloadTask obtains the stream playback address, if it is a seed file or a network video file, it obtains the local stream playback address of mini_thunder. Otherwise, it returns the stream playback source address directly.
public String getPlayUrl(){ if(this.isLocalMedia || this.mIsLiveMedia){ return this.getUrl(); }else if(this.taskId != 0L){ if(this.isNetworkDownloadTask){ return XLTaskHelper.instance().getLoclUrl(this.localSavePath + this.name); }else if(this.torrentInfo != null && this.currentPlayMediaIndex != -1){ for(PlayListItem item : getPlayList()){ if(item.getIndex() == this.currentPlayMediaIndex){ return XLTaskHelper.instance().getLoclUrl(this.localSavePath + item.getName()); } } } } return null; }
5. Method of calling the player
After the player is encapsulated, a line of code can be called externally to play the video:
XLVideoPlayActivity.intentTo(context, url, title);
Url parameters are supported live video sources, local files, seed files, or network video file addresses.
To view the playback effect, see TVRemoteIME APP (TV box installation ).
Vi. End
Open-source project address: TVRemoteIME
Note: Because this player belongs to the submodule project under the TVRemoteIME project, the project code is parasitic on it. However, currently, the TVRemoteIME code is not open-source for the time being. Later, it is determined whether the player is open-source based on actual conditions.