预览视频
预览视频是鼓励用户深入链接到电视应用的绝佳方式。 预览的范围可以从短片到完整的电影预告片。
在创建预览时,请考虑以下准则:
- 不要在预览中显示广告。 如果您在客户端缝合广告,请不要将它们粘贴到预览视频中。 如果您在服务器端使用stich广告,请为预览提供无广告视频。
- 为了获得最佳质量,预览视频应该是16:9或4:3。 请参阅视频节目属性以了解预览视频的建议尺寸。
- 当预览视频和海报画面具有不同的高宽比时,主屏幕会在播放预览之前将海报视图的大小调整为视频的宽高比。 该视频不是letterboxed。 例如,如果海报艺术比例是
ASPECT_RATIO_MOVIE_POSTER
(1:1.441),但是视频比例是16:9,则海报视图变换为16:9的区域。 - 当您创建预览时,其内容可以公开访问或受DRM保护。 每种情况下都适用不同的程序。 这个页面描述了两者。
在主屏幕上播放预览
如果您使用ExoPlayer支持的任何视频类型创建预览,并且预览可公开访问,则可以直接在主屏幕上播放预览。
构建PreviewProgram时,请使用setPreviewVideoUri()
并使用可公开访问的HTTPS URL,如下例所示。 预览可以是视频或音频 。
科特林
val previewVideoUrl = Uri.parse(“https://www.example.com/preview.mp4”)
val builder = PreviewProgram.Builder()
builder.setChannelId(渠道ID)
// ...
.setPreviewVideoUri(previewVideoUrl)
Java的
Uri previewVideoUrl = Uri.parse(“https://www.example.com/preview.mp4”);
PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(渠道ID)
// ...
.setPreviewVideoUri(Uri.parse(previewVideoUrl));
渲染表面上的预览
如果您的视频受DRM保护或者ExoPlayer不支持的媒体类型,请使用TvInputService
Android TV主屏幕通过调用onSetSurface()
将Surface
传递给您的服务。 您的应用程序直接在onTune()
这个表面上绘制视频。
直接表面渲染可让您的应用程序控制渲染的内容以及渲染方式。 您可以覆盖元数据,例如频道归因。
在清单中声明您的TvInputService
您的应用必须提供TvInputService
的实现,以便主屏幕可以呈现您的预览。在你的服务声明中,包含一个intent过滤器,它指定TvInputService
为意图执行的动作。 还将服务元数据声明为单独的XML资源。 以下示例中显示了服务声明,意图过滤器和服务元数据声明:
<service android:name =“。rich.PreviewInputService”
机器人:权限= “android.permission.BIND_TV_INPUT”>
<! - 系统用来启动我们的帐户服务所需的过滤器。 - >
<意图滤波器>
<action android:name =“android.media.tv.TvInputService”/>
</意图滤波器>
<! - 描述此输入的XML文件。 - >
<元数据
机器人:名字= “android.media.tv.input”
android:resource =“@ xml / previewinputservice”/>
</服务>
在单独的XML文件中定义服务元数据。 服务元数据文件位于您的应用程序的XML资源目录中,并且必须与您在清单中声明的资源的名称相匹配。 使用上例中的清单条目,您可以在res/xml/previewinputservice.xml
创建一个XML文件,并带有一个空的tv-input
标签:
<?xml version="1.0" encoding="utf-8"?> <tv-input/>
电视输入框架必须有这个标签。 但是,它仅用于配置直播频道。 由于您正在呈现视频,因此标记应该为空。
创建一个视频URI
为了表明您的预览视频应该由您的应用呈现,而不是Android TV主屏幕,您必须为PreviewProgram
创建一个视频URI。URI应以应用程序用于内容的标识符结束,以便稍后可以在TvInputService
检索内容。如果您的标识符是Long
类型,请使用TvContractCompat.buildPreviewProgramUri() :
科特林
val id:Long = 1L //内容标识符
val componentName = new ComponentName(context,PreviewVideoInputService.class)
val previewProgramVideoUri = TvContractCompat.buildPreviewProgramUri(id)
。建立在()
.appendQueryParameter(“input”,TvContractCompat.buildInputId(componentName))
。建立()
Java的
长ID = 1L; //内容标识符
ComponentName componentName = new ComponentName(context,PreviewVideoInputService.class);
previewProgramVideoUri = TvContractCompat.buildPreviewProgramUri(id)
。建立在()
.appendQueryParameter(“input”,TvContractCompat.buildInputId(componentName))
。建立();
如果您的标识符不是Long
类型,请使用Uri.withAppendedPath()
构建URI:
科特林
val previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI,“content-identifier”)
。建立在()
.appendQueryParameter(“input”,TvContractCompat.buildInputId(componentName))
。建立()
Java的
previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI,“content-identifier”)
。建立在()
.appendQueryParameter(“input”,TvContractCompat.buildInputId(componentName))
。建立();
您的应用程序调用onTune(Uri videoUri)
以使Android TV启动预览视频。
创建一个服务
以下示例显示如何扩展TvInputService
以创建您自己的PreviewInputService
请注意,该服务使用MediaPlayer
播放,但您的代码可以使用任何可用的视频播放器。
科特林
导入android.content.Context
导入android.media.MediaPlayer
导入android.media.tv.TvInputService
导入android.net.Uri
导入android.util.Log
导入android.view.Surface
导入java.io.IOException
类PreviewVideoInputService:TvInputService(){
重写fun onCreateSession(inputId:String):TvInputService.Session? {
返回PreviewSession(this)
}
私人内部类PreviewSession(
内部变量上下文:上下文
):TvInputService.Session(context){
内部var mediaPlayer:MediaPlayer? = MediaPlayer()
覆盖有趣的onRelease(){
媒体播放器?.release()
mediaPlayer = null
}
重写fun onTune(uri:Uri):Boolean {
//让TvInputService知道视频正在加载。
notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING)
//从TV Provider数据库获取流url
//用于内容://android.media.tv/preview_program/
val id = uri.lastPathSegment
//在后台加载视频。
retrieveYourVideoPreviewUrl(id){videoUri - >
如果(videoUri == null){
Log.d(TAG,“找不到视频$ id”)
notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN)
}
尝试{
mPlayer.setDataSource(getApplicationContext(),videoUri)
mPlayer.prepare()
mPlayer.start()
notifyVideoAvailable()
} catch(IOException e){
Log.e(标签,“无法准备媒体播放器”,e)
notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN)
}
}
返回true
}
覆盖乐趣onSetSurface(surface:Surface?):Boolean {
MEDIAPLAYER?.setSurface(表面)
返回true
}
覆盖乐趣onSetStreamVolume(音量:浮动){
//主屏幕可能会淡入淡出视频的音量。
//你的播放器应该相应地更新。
mediaPlayer?.setVolume(音量,音量)
}
在SetCaptionEnabled上重写fun(b:Boolean){
//在此处启用/停用字幕
}
}
伴侣对象{
private const val TAG =“PreviewInputService”
}
}
Java的
import android.content.Context;
import android.media.MediaPlayer;
import android.media.tv.TvInputService;
导入android.net.Uri;
导入android.support.annotation.Nullable;
导入android.util.Log;
导入android.view.Surface;
import java.io.IOException;
公共类PreviewVideoInputService继承TvInputService {
private static final String TAG =“PreviewVideoInputService”;
@Nullable
@覆盖
public Session onCreateSession(String inputId){
返回新的PreviewSession(this);
}
私人类PreviewSession继承TvInputService.Session {
私人MediaPlayer mPlayer;
PreviewSession(上下文上下文){
超级(上下文);
mPlayer = new MediaPlayer();
}
@覆盖
public boolean onTune(Uri channelUri){
//让TvInputService知道视频正在加载。
notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING);
//从TV Provider数据库获取流url
//用于内容://android.media.tv/preview_program/
String id = uri.getLastPathSegment();
//在后台加载视频。
retrieveYourVideoPreviewUrl(id,new MyCallback(){
public void callback(Uri videoUri){
如果(videoUri == null){
Log.d(TAG,“找不到视频”+ id);
notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
}
尝试{
mPlayer.setDataSource(getApplicationContext(),videoUri);
mPlayer.prepare();
mPlayer.start();
notifyVideoAvailable();
} catch(IOException e){
Log.e(标签,“无法准备媒体播放器”,e);
notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
}
}
});
返回true;
}
@覆盖
public boolean onSetSurface(@Nullable Surface surface){
if(mPlayer!= null){
mPlayer.setSurface(表面);
}
返回true;
}
@覆盖
public void onRelease(){
if(mPlayer!= null){
mPlayer.release();
}
mPlayer = null;
}
@覆盖
public void onSetStreamVolume(float volume){
if(mPlayer!= null){
//主屏幕可能会淡入淡出视频的音量。
//你的播放器应该相应地更新。
mPlayer.setVolume(volume,volume);
}
}
@覆盖
public void onSetCaptionEnabled(boolean enabled){
//在此处启用/停用字幕
}
}
}