一边播放一边下载视频

Posted

技术标签:

【中文标题】一边播放一边下载视频【英文标题】:Download video along with playing 【发布时间】:2015-12-19 13:18:19 【问题描述】:

我想在下载的同时实现在线视频播放功能。我的意思是应该使用同一个下载流来下载和播放,这样视频可以保存以供离线使用,并防止单独播放和下载的两倍数据成本。

到目前为止,我已经使用asyncTask 实现了视频下载并在OnPostExecute 上播放。以下是代码:

public class MainActivity extends AppCompatActivity 


private Button btnPlay;
private MediaPlayer player;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    outFilePath = getExternalFilesDir("/") + "/video.mp4";
    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        
    );

    prepareVideoView();



private VideoView videoView;
String videoPath = "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_5mb.mp4";
String outFilePath = "";//

private void prepareVideoView() 
    MediaController mediaController = new MediaController(this);
    videoView = (VideoView) findViewById(R.id.videoView);
    mediaController.setAnchorView(videoView);
    videoView.setMediaController(mediaController);
    btnPlay = (Button) findViewById(R.id.btnPlayVideo);
    btnPlay.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            new VideoDownloader().execute(videoPath);
        
    );

    videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() 
        @Override
        public void onPrepared(MediaPlayer mp) 
            player = mp;

            player.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() 
                @Override
                public void onVideoSizeChanged(MediaPlayer mp, int width, int height) 
                    Log.w("download","size changed");
                
            );
        
    );

File outFile;
class VideoDownloader extends AsyncTask<String, Integer, Void> 

    @Override
    protected Void doInBackground(String... params) 


        outFile = new File(outFilePath);
        FileOutputStream out = null;
        BufferedInputStream input = null;
        try 
            out = new FileOutputStream(outFile,true);

            try 
                URL url = new URL(videoPath);

                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) 
                    throw new RuntimeException("response is not http_ok");
                
                int fileLength = connection.getContentLength();

                input = new BufferedInputStream(connection.getInputStream());
                byte data[] = new byte[2048];
                long readBytes = 0;
                int len;
                boolean flag = true;
                int readb = 0;
                while ((len = input.read(data)) != -1) 
                    out.write(data,0,len);
                    readBytes += len;
   // Following commented code is to play video along with downloading but not working.
/*                      readb += len;
                    if(readb > 1000000)
                    
                        out.flush();
                        playVideo();
                        readb = 0;
                    
*/
                    Log.w("download",(readBytes/1024)+"kb of "+(fileLength/1024)+"kb");
                



             catch (MalformedURLException e) 
                e.printStackTrace();
             catch (IOException e) 
                e.printStackTrace();
             finally 
                if (out != null)
                    out.flush();
                    out.close();
                if(input != null)
                    input.close();
            
         catch (IOException e) 
            e.printStackTrace();
        

        return null;
    

    @Override
    protected void onPostExecute(Void aVoid) 
        super.onPostExecute(aVoid);
        Log.w("download", "Done");
       playVideo();

    


private void playVideo() 

    videoView.setVideoPath(outFile.getAbsolutePath());
    videoView.start();


上面的代码可以正常下载然后播放。 DoInBackground 的评论中有一些代码行,我试图实现我的目标,但它说“无法播放视频”。 有人知道解决方案吗?请帮帮我。

【问题讨论】:

您是在询问像 Youtube 中发生的那样流式传输视频吗? 我认为在 youtube 中只有流媒体。我需要的是仅使用一个输入流在线播放视频并将其保存以供离线使用。 您的playVideo() 方法使用带有setVideoPath() 的文件。换言之,playVideo()适用于磁盘上完全下载的视频。您需要将单独的帧和音频传递给媒体播放器进行流式传输,然后在查看后将这些字节简单地传递给文件以供离线使用。 您需要做的是在下载视频时,将帧流式传输到播放器,如@MeetTitan 所述。实际上,您需要在手机上创建一个流媒体服务器,将数据流式传输到您自己的播放器,而不是在服务器上进行流式传输。 @khetanrajesh 我已经实现了这个,如果你想看看它,请参考github.com/chandilsachin/VideoDownloadAndPlay 【参考方案1】:

您可以创建将保存流的本地代理。

创建两个后台线程:下载线程流式线程

流式线程中创建ServerSocket并流式传输刚刚下载的数据。

在 VideoView 中打开你的 ServerSocket 的 localhost url。

您将需要处理缓冲、同步线程等。

【讨论】:

我不想创建两个线程。我希望只有一个 inputStream 来节省双倍的数据消耗。顺便说一句,我不知道如何创建本地代理。解释将不胜感激。谢谢。 一个线程用于从互联网下载,第二个线程用于流式传输到媒体播放器 (VideoView) = 没有双重数据消耗。这里有使用 ServerSocket 的示例:***.com/questions/15541804/… MediaPlayer 仅接受 web url、fileDescripter 和本地文件 uri 来播放视频。那么 StreamingThread 将如何播放视频呢? 当您创建 ServerSocket 时,您将拥有 localhost url(即 127.0.0.1:6543/ 或 localhost:6543/)。您可以设置自己的端口(即 6543)或让系统为您分配一些空闲端口。 我按照你的建议做了。现在我有一个新问题,每当我点击本地套接字服务器链接时,都会在服务器端引发异常。看到这个问题***.com/questions/34728935/android-local-video-server【参考方案2】:

Milos Fec 的回答的帮助下,我解决了这个问题。 我必须创建两个线程,一个用于下载,另一个用于流式传输,通过 socketServer 下载内容,同时负责同步下载的数据和正在播放的数据。

我已将整个代码作为库放在 github check here

编辑:此库不适用于视频服务器通过将视频分成块等来限制下载的所有类型的视频......

我只用 mp4 测试过它。此库需要公共链接。

我在 Android 开发的早期就致力于此,只是为了学习本地服务器和远程服务器之间的同步。这个库有很大的改进空间,我没有做任何事情,因为还有其他选项可以满足相同的要求,而且我也没有足够的时间从我的其他东西中获得足够的时间。

【讨论】:

如何获取 serverPath?? 你能告诉我一些示例输入,我们需要在下面的代码中传递什么 videoService = VideoDownloadAndPlayService.startServer(getActivity(), videoPath,outFilePath, serverPath, new VideoDownloadAndPlayService.VideoStreamInterface() @Override public void onServerStart(String videoStreamUrl) // 使用 videoStreamUrl 通过媒体播放器播放视频 ); 什么 id server serverPath 我怎么能得到它???我正在使用火力基地 @Johndahat serverPath 是 http://localhost:portNo。检查这个使用这个库github.com/chandilsachin/VideoPlayerAndDownloaderDemo的演示应用程序。 @Johndahat 我的库有问题。我没有足够的时间来修复它们。我建议你看看这个github.com/danikula/AndroidVideoCache。

以上是关于一边播放一边下载视频的主要内容,如果未能解决你的问题,请参考以下文章

基于ffmpeg和libvlc的视频剪辑播放器

基于ffmpeg和libvlc的视频剪辑播放器

基于ffmpeg和libvlc的视频剪辑播放器

基于ffmpeg和libvlc的视频剪辑播放器

基于ffmpeg和libvlc的视频剪辑播放器

流媒体整理