android - 使用加密 key 在 exoplayer 中播放加密的 hls

标签 android amazon-web-services encryption exoplayer

我正在尝试使用 .m3u8 文件播放加密视频。我将视频存储在 AWS 中并创建了 .ts 文件和主播放列表。 AWS 为我提供了该加密视频文件的一些 key 。现在我必须在 exoplayer 中使用这些键。我尝试使用 Aes128DataSourceDrmSessionManager 但没有成功。

关键类型是:

Encryption Key: ####################################################################
Encryption Key MD5: ################
Encryption Initialization Vector : #############

下面是我用来播放 hls 视频的代码。它可以流畅地播放视频,没有任何问题。我只需要知道在哪里以及如何使用 key 来播放加密视频。

            String VIDEO_URL = "https://s3.amazonaws.com/######.###.##/videos/mobiletest/mobilemaster.m3u8";

            //Create a default TrackSelector
            BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
            TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
            TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

            // Create a default LoadControl
            LoadControl loadControl = new DefaultLoadControl();
            //Bis. Create a RenderFactory
            RenderersFactory renderersFactory = new DefaultRenderersFactory(this);


            //Create the player
            player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector, loadControl);
            simpleExoPlayerView = new SimpleExoPlayerView(this);
            simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);


            //Set media controller
            simpleExoPlayerView.setUseController(true);
            simpleExoPlayerView.requestFocus();

            // Bind the player to the view.
            simpleExoPlayerView.setPlayer(player);

            // Set the media source
            Uri mp4VideoUri = Uri.parse(VIDEO_URL);

            //Measures bandwidth during playback. Can be null if not required.
            DefaultBandwidthMeter bandwidthMeterA = new DefaultBandwidthMeter();

            //Produces DataSource instances through which media data is loaded.
            DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "PiwikVideoApp"), bandwidthMeterA);

            //Produces Extractor instances for parsing the media data.
            ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

            //FOR LIVE STREAM LINK:
            MediaSource videoSource = new HlsMediaSource(mp4VideoUri, dataSourceFactory, 1, null, null);
            final MediaSource mediaSource = videoSource;


            player.prepare(videoSource);

我已使用 AWS Elastic Transcoder 加密视频,并使用 exoplayer 版本:2.6.0

最佳答案

我已经找到解决办法了。您需要做的技巧是创建您自己的自定义数据源。您需要创建一个扩展 HttpDataSource.BaseFactory 的类,并从 DefaultHttpDataSourceFactory 添加一些代码。我知道这听起来很疯狂,但我已经用这种方法解决了。别担心,我将在此处粘贴该自定义类的完整代码。

import android.support.annotation.Nullable;

import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;

public class CustomDataSourcesFactory extends HttpDataSource.BaseFactory{
    private final String userAgent;
    private final @Nullable
    TransferListener listener;
    private final int connectTimeoutMillis;
    private final int readTimeoutMillis;
    private final boolean allowCrossProtocolRedirects;

    /**
     * Constructs a DefaultHttpDataSourceFactory. Sets {@link
     * DefaultHttpDataSource#DEFAULT_CONNECT_TIMEOUT_MILLIS} as the connection timeout, {@link
     * DefaultHttpDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read timeout and disables
     * cross-protocol redirects.
     *
     * @param userAgent The User-Agent string that should be used.
     */
    public CustomDataSourcesFactory(String userAgent) {
        this(userAgent, null);
    }

    /**
     * Constructs a DefaultHttpDataSourceFactory. Sets {@link
     * DefaultHttpDataSource#DEFAULT_CONNECT_TIMEOUT_MILLIS} as the connection timeout, {@link
     * DefaultHttpDataSource#DEFAULT_READ_TIMEOUT_MILLIS} as the read timeout and disables
     * cross-protocol redirects.
     *
     * @param userAgent The User-Agent string that should be used.
     * @param listener An optional listener.
     */
    public CustomDataSourcesFactory(String userAgent, @Nullable TransferListener listener) {
        this(userAgent, listener, DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
                DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, false);
    }

    /**
     * @param userAgent The User-Agent string that should be used.
     * @param connectTimeoutMillis The connection timeout that should be used when requesting remote
     *     data, in milliseconds. A timeout of zero is interpreted as an infinite timeout.
     * @param readTimeoutMillis The read timeout that should be used when requesting remote data, in
     *     milliseconds. A timeout of zero is interpreted as an infinite timeout.
     * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
     *     to HTTPS and vice versa) are enabled.
     */
    public CustomDataSourcesFactory(
            String userAgent,
            int connectTimeoutMillis,
            int readTimeoutMillis,
            boolean allowCrossProtocolRedirects) {
        this(
                userAgent,
                /* listener= */ null,
                connectTimeoutMillis,
                readTimeoutMillis,
                allowCrossProtocolRedirects);
    }

    /**
     * @param userAgent The User-Agent string that should be used.
     * @param listener An optional listener.
     * @param connectTimeoutMillis The connection timeout that should be used when requesting remote
     *     data, in milliseconds. A timeout of zero is interpreted as an infinite timeout.
     * @param readTimeoutMillis The read timeout that should be used when requesting remote data, in
     *     milliseconds. A timeout of zero is interpreted as an infinite timeout.
     * @param allowCrossProtocolRedirects Whether cross-protocol redirects (i.e. redirects from HTTP
     *     to HTTPS and vice versa) are enabled.
     */
    public CustomDataSourcesFactory(
            String userAgent,
            @Nullable TransferListener listener,
            int connectTimeoutMillis,
            int readTimeoutMillis,
            boolean allowCrossProtocolRedirects) {
        this.userAgent = userAgent;
        this.listener = listener;
        this.connectTimeoutMillis = connectTimeoutMillis;
        this.readTimeoutMillis = readTimeoutMillis;
        this.allowCrossProtocolRedirects = allowCrossProtocolRedirects;
    }

    @Override
    protected HttpDataSource createDataSourceInternal(
            HttpDataSource.RequestProperties defaultRequestProperties) {
        DefaultHttpDataSource defaultHttpDataSource = new DefaultHttpDataSource(userAgent, null, listener, connectTimeoutMillis,
                readTimeoutMillis, allowCrossProtocolRedirects, defaultRequestProperties);
        defaultHttpDataSource.setRequestProperty("your header", "your token");
        return defaultHttpDataSource;
    }}

你看到createDataSourceInternal方法了吗?我返回一个使用 header key 和 token defaultHttpDataSource.setRequestProperty("your header", "your token"); 初始化的 DefaultHttpDataSource 对象。因此,现在您的 exoplayer 将使用此 header 键和 token 值访问指控 URL,服务器端将检查该 header 键和 token 值以验证有效请求。您的 hls 播放列表(.m3u8) 包含指控 URL。 Exoplayer 自动使用此 URL。您所需要做的就是告诉玩家使用验证 key 。

这里再次是您的自定义数据源的使用代码:

//ExoPlayer implementation
    //Create a default TrackSelector
    BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
    TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
    TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

    // Create a default LoadControl
    LoadControl loadControl = new DefaultLoadControl();
    //Bis. Create a RenderFactory
    RenderersFactory renderersFactory = new DefaultRenderersFactory(this);


    //Create the player
    player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector, loadControl);
    simpleExoPlayerView = new SimpleExoPlayerView(this);
    simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);


    //Set media controller
    simpleExoPlayerView.setUseController(true);
    simpleExoPlayerView.requestFocus();

    // Bind the player to the view.
    simpleExoPlayerView.setPlayer(player);

    // Set the media source
    Uri mp4VideoUri = Uri.parse(VIDEO_URL);

    //DefaultHttpDataSource source = new DefaultHttpDataSource(Util.getUserAgent(this, "appAgent"), null);
    //source.setRequestProperty("header", "user token");

    //Measures bandwidth during playback. Can be null if not required.
    DefaultBandwidthMeter bandwidthMeterA = new DefaultBandwidthMeter();

    //DefaultDataSourceFactory o = new DefaultDataSourceFactory(this, null, new DefaultHttpDataSourceFactory(Util.getUserAgent(this, "appAgent"), bandwidthMeterA));
    CustomDataSourcesFactory o = new CustomDataSourcesFactory("Exoplayer");

    //Produces DataSource instances through which media data is loaded.
    DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "PiwikVideoApp"), bandwidthMeterA);

    //Produces Extractor instances for parsing the media data.
    ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

    //FOR LIVE STREAM LINK:
    MediaSource videoSource = new HlsMediaSource(mp4VideoUri, o, 1, null, null);
    final MediaSource mediaSource = videoSource;


    player.prepare(videoSource);

这个问题对我来说太关键了,因为我找不到任何教程、资源或想法来解决这个问题。我写这篇文章是因为我不想让像我这样的其他菜鸟遭受这种痛苦。

如果您还不够清楚,请随时在这里提问。我会进一步帮助您。我还有服务器端代码,以便从 AWS 加密 key 生成解密 key 。

关于android - 使用加密 key 在 exoplayer 中播放加密的 hls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54128394/

相关文章:

android - Kotlin 自定义对话框参数指定为非空

android - 从 Activity 调用 fragment 方法时出现空指针异常

php - 在 Javascript 和 PHP 之间混淆 POST 变量

android - 安卓的sqlite加密

swift - 无法将加密数据转换为字符串

android - ViewPager fragment 都引用相同的 RecyclerView 和/或适配器

Android 布局背景 alpha

amazon-web-services - SNS 中的订阅已存在,并且需要使用 1 个使用 cloudformation 的订阅

ruby - Ubuntu 20.0LTS 上的 AWS CodeDeploy-Agenten,Ruby 错误

javascript - 在 Node 中解析 SQSretrieveMessages