如何在Android中的ExoPlayer中播放Youtube视频?

Ami*_*ati 36 java youtube android exoplayer

我试图在exoplayer中播放youtube视频,但这里有一些混乱我不知道什么是DASH url,我只有真正的youtube网址,如" https://www.youtube.com/watch?v=v1uyQZNg2vE ",我不知道如何生成破折号网址形式真实的网址.

短划线网址:

new Sample("Google Glass",
        "http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?"
        + "as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,as&ip=0.0.0.0&"
        + "ipbits=0&expire=19000000000&signature=255F6B3C07C753C88708C07EA31B7A1A10703C8D."
        + "2D6A28B21F921D0B245CDCF36F7EB54A2B5ABFC2&key=ik0", DemoUtil.TYPE_DASH),
Run Code Online (Sandbox Code Playgroud)

真实网址:

 https://www.youtube.com/watch?v=v1uyQZNg2vE
Run Code Online (Sandbox Code Playgroud)

MAR*_*MAB 12

我写过一个课程,使用http://www.youtube.com/get_video_info?&video_id=[video_id]&el=info&ps=default&eurl=&gl=US&hl=en url与DASH和HLS等格式检索实际的YouTube视频流网址视频ID由Karim Abdell Salam描述.我还在使用ExoPlayer的应用程序中测试了URL ,它可以工作:

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Map;
import java.util.TreeMap;

/**
 * Represents youtube video information retriever.
 */
public class YouTubeVideoInfoRetriever
{
    private static final String URL_YOUTUBE_GET_VIDEO_INFO = "http://www.youtube.com/get_video_info?&video_id=";

    public static final String KEY_DASH_VIDEO = "dashmpd";
    public static final String KEY_HLS_VIDEO = "hlsvp";

    private TreeMap<String, String> kvpList = new TreeMap<>();

    public void retrieve(String videoId) throws IOException
    {
        String targetUrl = URL_YOUTUBE_GET_VIDEO_INFO + videoId+"&el=info&ps=default&eurl=&gl=US&hl=en";
        SimpleHttpClient client = new SimpleHttpClient();
        String output = client.execute(targetUrl, SimpleHttpClient.HTTP_GET, SimpleHttpClient.DEFAULT_TIMEOUT);
        parse(output);
    }

    public String getInfo(String key)
    {
        return kvpList.get(key);
    }

    public void printAll()
    {
        System.out.println("TOTAL VARIABLES=" + kvpList.size());

        for(Map.Entry<String, String> entry : kvpList.entrySet())
        {
            System.out.print( "" + entry.getKey() + "=");
            System.out.println("" + entry.getValue() + "");
        }
    }

    private void parse(String data) throws UnsupportedEncodingException
    {
        String[] splits = data.split("&");
        String kvpStr = "";

        if(splits.length < 1)
        {
            return;
        }

        kvpList.clear();

        for(int i = 0; i < splits.length; ++i)
        {
            kvpStr = splits[i];

            try
            {
                // Data is encoded multiple times
                kvpStr = URLDecoder.decode(kvpStr, SimpleHttpClient.ENCODING_UTF_8);
                kvpStr = URLDecoder.decode(kvpStr, SimpleHttpClient.ENCODING_UTF_8);

                String[] kvpSplits = kvpStr.split("=", 2);

                if(kvpSplits.length == 2)
                {
                    kvpList.put(kvpSplits[0], kvpSplits[1]);
                }
                else if(kvpSplits.length == 1)
                {
                    kvpList.put(kvpSplits[0], "");
                }
            }
            catch (UnsupportedEncodingException ex)
            {
                throw ex;
            }
        }
    }

    public static class SimpleHttpClient
    {
        public static final String ENCODING_UTF_8 = "UTF-8";
        public static final int DEFAULT_TIMEOUT = 10000;

        public static final String HTTP_GET = "GET";

        public String execute(String urlStr, String httpMethod, int timeout) throws IOException
        {
            URL url = null;
            HttpURLConnection conn = null;
            InputStream inStream = null;
            OutputStream outStream = null;
            String response = null;

            try
            {
                url = new URL(urlStr);
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(timeout);
                conn.setRequestMethod(httpMethod);

                inStream = new BufferedInputStream(conn.getInputStream());
                response = getInput(inStream);
            }
            finally
            {
                if(conn != null && conn.getErrorStream() != null)
                {
                    String errorResponse = " : ";
                    errorResponse = errorResponse + getInput(conn.getErrorStream());
                    response = response + errorResponse;
                }

                if (conn != null)
                {
                    conn.disconnect();
                }
            }

            return response;
        }

        private String getInput(InputStream in) throws IOException
        {
            StringBuilder sb = new StringBuilder(8192);
            byte[] b = new byte[1024];
            int bytesRead = 0;

            while (true)
            {
                bytesRead = in.read(b);
                if (bytesRead < 0)
                {
                    break;
                }
                String s = new String(b, 0, bytesRead, ENCODING_UTF_8);
                sb.append(s);
            }

            return sb.toString();
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

这是测试代码:

public static void main(String[] args)
{
    String youTubeVideoID = "v1uyQZNg2vE";

    YouTubeVideoInfoRetriever retriever = new YouTubeVideoInfoRetriever();

    try
    {
        retriever.retrieve(youTubeVideoID);
        System.out.println(retriever.getInfo(YouTubeVideoInfoRetriever.KEY_DASH_VIDEO));
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @MARK002-MAB 感谢您的回复,我有 youtube 网址,我如何在 exoplayer 中玩 (2认同)
  • 如果我使用这种方法,这是否会违反 youtube 服务条款并导致我的应用程序从 Play 商店中撤出? (2认同)
  • @MichaelStoddart 是的。这是一种可能性。我在某处读到,使用所提供的方法以外的方法可能会构成违规。它适用于所有 Google 服务和 API。 (2认同)
  • 这不再起作用了 (2认同)

Kar*_*lam 8

我有同样的问题,但我终于找到了最简单的解决方案,它的工作非常好

  1. 首先你需要调用这个网址..

    HTTP GET:https://www.youtube.com/get_video_info?& video_id = [ video_id] & el = info & ps = default & nerl =& gl = US &hl = zh- CN

并且不要忘记用目标ID更改最后一个id.

  1. 现在你会注意到下载一个名为get_video_info但没有extesion的文件.
  2. 尝试使用记事本等打开此文件.
  3. 现在你有了正确的数据,但你无法阅读,因为它的编码你需要HTML解码器来reed这个数据使用这个:http: //meyerweb.com/eric/tools/dencoder/

- 只需粘贴数据并按几次解码,以确保解码良好

最后搜索一个名为dashmpd的键

并享受你的URL

或使用此简单解决方案

private void extractYoutubeUrl() {
    @SuppressLint("StaticFieldLeak") YouTubeExtractor mExtractor = new YouTubeExtractor(this) {
        @Override
        protected void onExtractionComplete(SparseArray<YtFile> sparseArray, VideoMeta videoMeta) {
            if (sparseArray != null) {
                playVideo(sparseArray.get(17).getUrl());
            }
        }
    };
    mExtractor.extract(mYoutubeLink, true, true);
Run Code Online (Sandbox Code Playgroud)
implementation 'com.github.HaarigerHarald:android-youtubeExtractor:v1.7.0'
Run Code Online (Sandbox Code Playgroud)

  • 不工作`reason=Invalid+parameters.&amp;status=fail&amp;errorcode=2` 这就是我得到的 (5认同)
  • 已经过时并且不再有效。 (3认同)

GAG*_*'sB 7

您必须从youtube URL(在您的情况下是真实URL)获取HTTP响应,然后搜索"url_encoded_fmt_stream_map"部分.在该部分中,您将获得一个需要解码两次的URI,以获取您正在寻找的DASH URL.


saj*_*asi 5

要在 exoplayer 中播放 youtube 视频,我们可以使用这个库

https://github.com/HaarigerHarald/android-youtubeExtractor
Run Code Online (Sandbox Code Playgroud)

只需获取这样的 url,然后在 exoplyer 中播放

String youtubeLink = "http://youtube.com/watch?v=xxxx";

new YouTubeExtractor(this) {
    @Override
    public void onExtractionComplete(SparseArray<YtFile> ytFiles, VideoMeta vMeta) {
        if (ytFiles != null) {
            int itag = 22;
        String downloadUrl = ytFiles.get(itag).getUrl();
        }
    }
}.extract(youtubeLink, true, true);
Run Code Online (Sandbox Code Playgroud)

  • 我不明白为什么将 itag 变量声明为 22 (4认同)

Ham*_*tah 5

这是使用的库

implementation 'com.github.HaarigerHarald:android-youtubeExtractor:master-SNAPSHOT'
Run Code Online (Sandbox Code Playgroud)

这是基本 url 添加到他们的视频 id

val YouTubeBase="https://www.youtube.com/watch?v="
Run Code Online (Sandbox Code Playgroud)

这是使用的库, 我将使用循环来获取所有视频质量(420,720,180),因为如果视频不包含 1080,则不适用于您,这样我将循环获取所有质量, 但如果发现更高质量,它将选择最佳质量,如果你想获得低质量,你可以通过称为 iTags 的反向数组来编辑它

    object : YouTubeExtractor(requireContext()) {
        override fun onExtractionComplete(
            ytFiles: SparseArray<YtFile>?,
            videoMeta: VideoMeta?
        ) {
            if (ytFiles != null) {

                val iTag = 137//tag of video 1080
                val audioTag = 140 //tag m4a audio
                // 720, 1080, 480
                var videoUrl = ""
                val iTags: List<Int> = listOf(22, 137, 18)
                for (i in iTags) {
                    val ytFile = ytFiles.get(i)
                    if (ytFile != null) {
                        val downloadUrl = ytFile.url
                        if (downloadUrl != null && downloadUrl.isNotEmpty()) {
                            videoUrl = downloadUrl
                        }
                    }
                }
                if (videoUrl == "")
                    videoUrl = ytFiles[iTag].url
                val audioUrl = ytFiles[audioTag].url
                val audioSource: MediaSource = ProgressiveMediaSource
                    .Factory(DefaultHttpDataSource.Factory())
                    .createMediaSource(MediaItem.fromUri(audioUrl))
                val videoSource: MediaSource = ProgressiveMediaSource
                    .Factory(DefaultHttpDataSource.Factory())
                    .createMediaSource(MediaItem.fromUri(videoUrl))
                player?.setMediaSource(
                    MergingMediaSource(true, videoSource, audioSource), true
                )
            }
        }

    }.extract(youtubeLink)
Run Code Online (Sandbox Code Playgroud)

这是我在上一个项目中的代码,我希望能帮助你使用 Exo 播放器使用库

package com.hamdy.showtime.ui.ui.video_player

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.exoplayer2.ExoPlayer
import com.hamdy.showtime.databinding.FragmentVideoPlayerBinding
import at.huber.youtubeExtractor.VideoMeta
import at.huber.youtubeExtractor.YtFile
import android.util.SparseArray
import at.huber.youtubeExtractor.YouTubeExtractor
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.MergingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.util.Util
import com.hamdy.showtime.ui.util.YouTubeBase


class VideoPlayerFragment : Fragment(), Player.Listener {
    private lateinit var youtubeLink: String
    private lateinit var binding: FragmentVideoPlayerBinding
    var player: ExoPlayer? = null
    private var playWhenReady = true
    private var currentWindow = 0
    private var playbackPosition = 0L

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentVideoPlayerBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        youtubeLink = YouTubeBase + arguments?.get("url").toString()

        initializePlayer()

    }

    private fun initializePlayer() {
        player = ExoPlayer.Builder(requireContext()).build()
        binding.videoView.player = player

        object : YouTubeExtractor(requireContext()) {
            override fun onExtractionComplete(
                ytFiles: SparseArray<YtFile>?,
                videoMeta: VideoMeta?
            ) {
                if (ytFiles != null) {

                    val iTag = 137//tag of video 1080
                    val audioTag = 140 //tag m4a audio
                    // 720, 1080, 480
                    var videoUrl = ""
                    val iTags: List<Int> = listOf(22, 137, 18)
                    for (i in iTags) {
                        val ytFile = ytFiles.get(i)
                        if (ytFile != null) {
                            val downloadUrl = ytFile.url
                            if (downloadUrl != null && downloadUrl.isNotEmpty()) {
                                videoUrl = downloadUrl
                            }
                        }
                    }
                    if (videoUrl == "")
                        videoUrl = ytFiles[iTag].url
                    val audioUrl = ytFiles[audioTag].url
                    val audioSource: MediaSource = ProgressiveMediaSource
                        .Factory(DefaultHttpDataSource.Factory())
                        .createMediaSource(MediaItem.fromUri(audioUrl))
                    val videoSource: MediaSource = ProgressiveMediaSource
                        .Factory(DefaultHttpDataSource.Factory())
                        .createMediaSource(MediaItem.fromUri(videoUrl))
                    player?.setMediaSource(
                        MergingMediaSource(true, videoSource, audioSource), true
                    )
                    player?.prepare()
                    player?.playWhenReady = playWhenReady
                    player?.seekTo(currentWindow, playbackPosition)
                    player?.addListener(this@VideoPlayerFragment)
                }
            }

        }.extract(youtubeLink)

    }

    override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
        if (playbackState == Player.STATE_READY) {
            binding.progressBar.visibility = View.INVISIBLE
        } else {
            binding.progressBar.visibility = View.VISIBLE
        }
    }


    override fun onStart() {
        super.onStart()
        if (Util.SDK_INT >= 24 || player == null) {
            initializePlayer()

        }
    }

    override fun onResume() {
        super.onResume()
        if (Util.SDK_INT < 24 || player == null) {
            initializePlayer()

        }
    }

    override fun onPause() {
        if (Util.SDK_INT < 24) releasePlayer()
        super.onPause()
    }

    private fun releasePlayer() {
        if (player != null) {
            playWhenReady = player!!.playWhenReady
            playbackPosition = player!!.currentPosition
            currentWindow = player!!.currentMediaItemIndex
            player?.release()
            player = null
        }

    }
}
Run Code Online (Sandbox Code Playgroud)