android 视频预览,预览视频  |  Android 开发者  |  Android Developers

如需鼓励用户访问您的 TV 应用中的深层链接,预览视频是一种不错的方法。

预览内容可以是简短的视频剪辑,也可以是完整的电影预告片。

在创建预览时,请注意以下准则:

不要在预览中显示广告。如果您在客户端拼接广告,请勿将它们拼接到预览视频中。如果您在服务器端拼接广告,请提供无广告的预览视频。

为获得最佳品质,预览视频的宽高比应为 16:9 或 4:3。请参阅视频节目属性,以获取预览视频的建议尺寸。

当预览视频和海报图片具有不同的宽高比时,在播放预览视频之前,主屏幕会将海报视图调整到视频的宽高比。

视频不是信箱模式的。例如,如果海报图片宽高比是 ASPECT_RATIO_MOVIE_POSTER (1:1.441),但视频宽高比是 16:9,则海报视图会转换为 16:9 区域。

在您创建预览时,其内容可供公开访问,也可以受 DRM 保护。每种情形采用的步骤不同。本页对两者都做了介绍。

在主屏幕中播放预览

如果您使用 ExoPlayer 支持的任何视频类型创建预览,并且预览可供公开访问,那么您可以直接在主屏幕中播放预览。

当您构建 PreviewProgram 时,请将 setPreviewVideoUri() 用于可公开访问的 HTTPS 网址,如以下示例所示。预览可以是视频或音频。

Kotlin

val previewVideoUrl = Uri.parse("https://www.example.com/preview.mp4")

val builder = PreviewProgram.Builder()

builder.setChannelId(channelId)

// ...

.setPreviewVideoUri(previewVideoUrl)Java

Uri previewVideoUrl = Uri.parse("https://www.example.com/preview.mp4");

PreviewProgram.Builder builder = new PreviewProgram.Builder();

builder.setChannelId(channelId)

// ...

.setPreviewVideoUri(Uri.parse(previewVideoUrl));

在 Surface 上呈现预览

如果您的视频受 DRM 保护,或不是 ExoPlayer 支持的媒体类型,请使用

通过直接在 Surface 上呈现,您的应用可以控制呈现的内容和方式。您可以叠加频道归因等元数据。

在清单中声明 TvInputService

您的应用必须提供

在服务声明中,请添加一个 intent 过滤器,将

android:permission="android.permission.BIND_TV_INPUT">

android:name="android.media.tv.input"

android:resource="@xml/previewinputservice" />

在单独的 XML 文件中定义服务元数据。

服务元数据文件位于您的应用的 XML 资源目录中,并且必须与您在清单中声明的资源名称相匹配。利用上例中的清单条目,您可以在 res/xml/previewinputservice.xml 创建一个含有空 tv-input 标记的 XML 文件:

TV 输入框架必须包含这个标记。不过,它仅用于配置直播频道。由于您要呈现的是视频,因此该标记应为空。

创建视频 URI

如需指明您的预览视频应通过您的应用而非 Android TV 主屏幕来呈现,您必须为 PreviewProgram 创建一个视频 URI。此 URI 应当以您的应用用于内容的标识符结尾,以便您可以稍后在 TvInputService 中检索该内容。

Kotlin

val id: Long = 1L // content identifier

val componentName = new ComponentName(context, PreviewVideoInputService.class)

val previewProgramVideoUri = TvContractCompat.buildPreviewProgramUri(id)

.buildUpon()

.appendQueryParameter("input", TvContractCompat.buildInputId(componentName))

.build()Java

Long id = 1L; // content identifier

ComponentName componentName = new ComponentName(context, PreviewVideoInputService.class);

previewProgramVideoUri = TvContractCompat.buildPreviewProgramUri(id)

.buildUpon()

.appendQueryParameter("input", TvContractCompat.buildInputId(componentName))

.build();

如果标识符不是 Long 类型,请使用

Kotlin

val previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI, "content-identifier")

.buildUpon()

.appendQueryParameter("input", TvContractCompat.buildInputId(componentName))

.build()Java

previewProgramVideoUri = Uri.withAppendedPath(PreviewPrograms.CONTENT_URI, "content-identifier")

.buildUpon()

.appendQueryParameter("input", TvContractCompat.buildInputId(componentName))

.build();

您的应用通过调用

创建服务

以下示例展示了如何扩展 TvInputService 来创建您自己的 PreviewInputService。注意,该服务使用 MediaPlayer 进行播放,但您的代码可以使用任何可用的视频播放器。

Kotlin

import android.content.Context

import android.media.MediaPlayer

import android.media.tv.TvInputService

import android.net.Uri

import android.util.Log

import android.view.Surface

import java.io.IOException

class PreviewVideoInputService : TvInputService() {

override fun onCreateSession(inputId: String): TvInputService.Session? {

return PreviewSession(this)

}

private inner class PreviewSession(

internal var context: Context

) : TvInputService.Session(context) {

internal var mediaPlayer: MediaPlayer? = MediaPlayer()

override fun onRelease() {

mediaPlayer?.release()

mediaPlayer = null

}

override fun onTune(uri: Uri): Boolean {

// Let the TvInputService know that the video is being loaded.

notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING)

// Fetch the stream url from the TV Provider database

// for content://android.media.tv/preview_program/val id = uri.lastPathSegment

// Load your video in the background.

retrieveYourVideoPreviewUrl(id) { videoUri ->

if (videoUri == null) {

Log.d(TAG, "Could not find video $id")

notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN)

}

try {

mPlayer.setDataSource(getApplicationContext(), videoUri)

mPlayer.prepare()

mPlayer.start()

notifyVideoAvailable()

} catch (IOException e) {

Log.e(TAG, "Could not prepare media player", e)

notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN)

}

}

return true

}

override fun onSetSurface(surface: Surface?): Boolean {

mediaPlayer?.setSurface(surface)

return true

}

override fun onSetStreamVolume(volume: Float) {

// The home screen may fade in and out the video's volume.

// Your player should be updated accordingly.

mediaPlayer?.setVolume(volume, volume)

}

override fun onSetCaptionEnabled(b: Boolean) {

// enable/disable captions here

}

}

companion object {

private const val TAG = "PreviewInputService"

}

}Java

import android.content.Context;

import android.media.MediaPlayer;

import android.media.tv.TvInputService;

import android.net.Uri;

import android.support.annotation.Nullable;

import android.util.Log;

import android.view.Surface;

import java.io.IOException;

public class PreviewVideoInputService extends TvInputService {

private static final String TAG = "PreviewVideoInputService";

@Nullable

@Override

public Session onCreateSession(String inputId) {

return new PreviewSession(this);

}

private class PreviewSession extends TvInputService.Session {

private MediaPlayer mPlayer;

PreviewSession(Context context) {

super(context);

mPlayer = new MediaPlayer();

}

@Override

public boolean onTune(Uri channelUri) {

// Let the TvInputService know that the video is being loaded.

notifyVideoUnavailable(VIDEO_UNAVAILABLE_REASON_TUNING);

// Fetch the stream url from the TV Provider database

// for content://android.media.tv/preview_program/String id = uri.getLastPathSegment();

// Load your video in the background.

retrieveYourVideoPreviewUrl(id, new MyCallback() {

public void callback(Uri videoUri) {

if (videoUri == null) {

Log.d(TAG, "Could not find video" + id);

notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);

}

try {

mPlayer.setDataSource(getApplicationContext(), videoUri);

mPlayer.prepare();

mPlayer.start();

notifyVideoAvailable();

} catch (IOException e) {

Log.e(TAG, "Could not prepare media player", e);

notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);

}

}

});

return true;

}

@Override

public boolean onSetSurface(@Nullable Surface surface) {

if (mPlayer != null) {

mPlayer.setSurface(surface);

}

return true;

}

@Override

public void onRelease() {

if (mPlayer != null) {

mPlayer.release();

}

mPlayer = null;

}

@Override

public void onSetStreamVolume(float volume) {

if (mPlayer != null) {

// The home screen may fade in and out the video's volume.

// Your player should be updated accordingly.

mPlayer.setVolume(volume, volume);

}

}

@Override

public void onSetCaptionEnabled(boolean enabled) {

// enable/disable captions here

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值