`

下载远程视频完成后进行播放(SurfaceView)

阅读更多

1.上代码:
package irdc.ex08_15;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.graphics.PixelFormat;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.webkit.URLUtil;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;

/* Activity实现SurfaceHolder.Callback */
public class PlayUrlVideo extends Activity implements SurfaceHolder.Callback
{
  private TextView mTextView01;
  private EditText mEditText01;

  /* 创建MediaPlayer对象 */
  private MediaPlayer mMediaPlayer01;

  /* 用以显示MediaPlayer的SurfaceView */
  private SurfaceView mSurfaceView01;

  /* SurfaceHolder对象 */
  private SurfaceHolder mSurfaceHolder01;

  //视频控制的几个按钮
  private ImageButton mPlay, mReset, mPause, mStop;

  /* 识别MediaPlayer是否已被释放 */
  private boolean bIsReleased = false;

  /* 识别MediaPlayer是否正处于暂停 */
  private boolean bIsPaused = false;

  /* LogCat输出TAG filter */
  private static final String TAG = "*****MediaPlayer*****";

  private String currentFilePath = "";

  //保存下载文件临时路径
  private String currentTempFilePath = "";
  private String strVideoURL = "";

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    /* 将.3gp图像文件存放URL网址 */
    strVideoURL = "http://www.dubblogs.cc:8751/Android/Test/Media/3gp/test.3gp";

    mTextView01 = (TextView) findViewById(R.id.myTextView1);
    mEditText01 = (EditText) findViewById(R.id.myEditText1);
    mEditText01.setText(strVideoURL);

    /* 绑定Layout上的SurfaceView */
    mSurfaceView01 = (SurfaceView) findViewById(R.id.mSurfaceView1);

    // 这句我还看出到底起什么作用
    getWindow().setFormat(PixelFormat.TRANSPARENT);

    /* 设置SurfaceHolder为Layout SurfaceView */
    mSurfaceHolder01 = mSurfaceView01.getHolder();
    mSurfaceHolder01.addCallback(this);

    // 影片指定其为固定比例
    mSurfaceHolder01.setFixedSize(160, 128);
    mSurfaceHolder01.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    mPlay = (ImageButton) findViewById(R.id.play);
    mReset = (ImageButton) findViewById(R.id.reset);
    mPause = (ImageButton) findViewById(R.id.pause);
    mStop = (ImageButton) findViewById(R.id.stop);

    /* 播放按钮 */
    mPlay.setOnClickListener(new ImageButton.OnClickListener()
    {
      public void onClick(View view)
      {
//判断SD卡是否存在
        if (checkSDCard())
        {
          strVideoURL = mEditText01.getText().toString();
//开始下载video
          playVideo(strVideoURL);
          mTextView01.setText(R.string.str_play);
        } else
        {
          mTextView01.setText(R.string.str_err_nosd);
        }
      }
    });

    /* 重新播放按钮 */
    mReset.setOnClickListener(new ImageButton.OnClickListener()
    {
      public void onClick(View view)
      {
        if (checkSDCard())
        {
          if (bIsReleased == false)
          {
            if (mMediaPlayer01 != null)
            {
//回到起始点开始重新播放
              mMediaPlayer01.seekTo(0);
              mTextView01.setText(R.string.str_play);
            }
          }
        } else
        {
          mTextView01.setText(R.string.str_err_nosd);
        }
      }
    });

    /* 暂停按钮 */
    mPause.setOnClickListener(new ImageButton.OnClickListener()
    {
      public void onClick(View view)
      {
        if (checkSDCard())
        {
          if (mMediaPlayer01 != null)
          {
            if (bIsReleased == false)
            {
              if (bIsPaused == false)
              {
                mMediaPlayer01.pause();
                bIsPaused = true;
                mTextView01.setText(R.string.str_pause);
              } else if (bIsPaused == true)
              {
                mMediaPlayer01.start();
                bIsPaused = false;
                mTextView01.setText(R.string.str_play);
              }
            }
          }
        } else
        {
          mTextView01.setText(R.string.str_err_nosd);
        }
      }
    });

    /* 终止按钮 */
    mStop.setOnClickListener(new ImageButton.OnClickListener()
    {
      public void onClick(View view)
      {
        if (checkSDCard())
        {
          try
          {
            if (mMediaPlayer01 != null)
            {
              if (bIsReleased == false)
              {
                mMediaPlayer01.seekTo(0);
                mMediaPlayer01.pause();
                mTextView01.setText(R.string.str_stop);
              }
            }
          } catch (Exception e)
          {
            mTextView01.setText(e.toString());
            Log.e(TAG, e.toString());
            e.printStackTrace();
          }
        } else
        {
          mTextView01.setText(R.string.str_err_nosd);
        }
      }
    });
  }

  /* 自定义下载URL影片并播放 */
  private void playVideo(final String strPath)
  {
    try
    {
      /* 若传入的strPath为现有播放的连接,则直接播放 */
      if (strPath.equals(currentFilePath) && mMediaPlayer01 != null)
      {
        mMediaPlayer01.start();
        return;
      } else if (mMediaPlayer01 != null)
      {
        mMediaPlayer01.stop();
      }

      currentFilePath = strPath;

      /* 重新构建MediaPlayer对象 */
      mMediaPlayer01 = new MediaPlayer();
      /* 设置播放音量 */
      mMediaPlayer01.setAudioStreamType(2);

      /* 设置显示于SurfaceHolder */
      mMediaPlayer01.setDisplay(mSurfaceHolder01);

      mMediaPlayer01.setOnErrorListener(new MediaPlayer.OnErrorListener()
      {
        // @Override
        public boolean onError(MediaPlayer mp, int what, int extra)
        {
          // TODO Auto-generated method stub
          Log.i(TAG, "Error on Listener, what: " + what + "extra: " + extra);
          return false;
        }
      });

      mMediaPlayer01
          .setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener()
          {
            // @Override
            public void onBufferingUpdate(MediaPlayer mp, int percent)
            {
              // TODO Auto-generated method stub
              Log.i(TAG, "Update buffer: " + Integer.toString(percent) + "%");
            }
          });

      mMediaPlayer01
          .setOnCompletionListener(new MediaPlayer.OnCompletionListener()
          {
            @Override
            public void onCompletion(MediaPlayer mp)
            {
              // TODO Auto-generated method stub
              Log.i(TAG, "mMediaPlayer01 Listener Completed");
              mTextView01.setText(R.string.str_done);
            }
          });

      mMediaPlayer01.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
      {
        // @Override
        public void onPrepared(MediaPlayer mp)
        {
          // TODO Auto-generated method stub
          Log.i(TAG, "Prepared Listener");
        }
      });

      Runnable r = new Runnable()
      {
        public void run()
        {
          try
          {
            /* 在线程运行中,调用自定义函数下载 */
            setDataSource(strPath);
            /* 下载完后才会调用prepare */
            mMediaPlayer01.prepare();
            Log.i(TAG, "Duration: " + mMediaPlayer01.getDuration());
            mMediaPlayer01.start();
            bIsReleased = false;
          } catch (Exception e)
          {
            Log.e(TAG, e.getMessage(), e);
          }
        }
      };
//新开启一个线程进行视频下载(增强用户体验)
      new Thread(r).start();
    } catch (Exception e)
    {
      if (mMediaPlayer01 != null)
      {
        mMediaPlayer01.stop();
        mMediaPlayer01.release();
      }
    }
  }

  /* 自定义setDataSource,由线程启动 */
  private void setDataSource(String strPath) throws Exception
  {
//判断地址是否合法
    if (!URLUtil.isNetworkUrl(strPath))
    {
//这里理解为不是合法网址,就传递的local地址
      mMediaPlayer01.setDataSource(strPath);
    } else
    {
      if (bIsReleased == false)
      {
        URL myURL = new URL(strPath);
        URLConnection conn = myURL.openConnection();
        conn.connect();
        InputStream is = conn.getInputStream();
//这里可以通过conn.getContentLength()来识别源字节大小,便于添加下载进度条
        if (is == null)
        {
          throw new RuntimeException("stream is null");
        }
//获取文件名扩展名,创建临时文件
        File myFileTemp = File.createTempFile("hippoplayertmp", "."
            + getFileExtension(strPath));
//获取文件绝对路径
        currentTempFilePath = myFileTemp.getAbsolutePath();

        /* currentTempFilePath = /sdcard/mediaplayertmp39327.dat */
//构建一个输出流写文件
        FileOutputStream fos = new FileOutputStream(myFileTemp);
        byte buf[] = new byte[128];
        do
        {
          int numread = is.read(buf);
          if (numread <= 0)
          {
            break;
          }
          fos.write(buf, 0, numread);
        } while (true);
//下载完成进行MediaPlayer源设置
        mMediaPlayer01.setDataSource(currentTempFilePath);
        try
        {
          is.close();
        } catch (Exception ex)
        {
          Log.e(TAG, "error: " + ex.getMessage(), ex);
        }
      }
    }
  }
//获取下载文件后缀名
  private String getFileExtension(String strFileName)
  {
    File myFile = new File(strFileName);
    String strFileExtension = myFile.getName();
    strFileExtension = (strFileExtension.substring(strFileExtension
        .lastIndexOf(".") + 1)).toLowerCase();

    if (strFileExtension == "")
    {
      /* 若无法顺利取得扩展名,默认为.dat */
      strFileExtension = "dat";
    }
    return strFileExtension;
  }

  private boolean checkSDCard()
  {
    /* 判断存储卡是否存在 */
    if (android.os.Environment.getExternalStorageState().equals(
        android.os.Environment.MEDIA_MOUNTED))
    {
      return true;
    } else
    {
      return false;
    }
  }

  // @Override
  public void surfaceChanged(SurfaceHolder surfaceholder, int format, int w,
      int h)
  {
    // TODO Auto-generated method stub
    Log.i(TAG, "Surface Changed");
  }

  // @Override
  public void surfaceCreated(SurfaceHolder surfaceholder)
  {
    // TODO Auto-generated method stub
    Log.i(TAG, "Surface Changed");
  }

  // @Override
  public void surfaceDestroyed(SurfaceHolder surfaceholder)
  {
    // TODO Auto-generated method stub
    Log.i(TAG, "Surface Changed");
  }
//当程序停止后,进行MediaPlayer的资源释放操作
  @Override
  protected void onStop()
  {
    super.onStop();
    if (mMediaPlayer01 != null)
    {
      mMediaPlayer01.stop();
      mMediaPlayer01.release();
    }
    this.finish();

  }
}

2.main.xml文件内容比较简单
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:background="@drawable/white" android:orientation="vertical"
	android:layout_width="fill_parent" android:layout_height="fill_parent">
	<TextView android:id="@+id/myTextView1" android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:textColor="@drawable/blue"
		android:text="@string/hello" />
	<EditText android:id="@+id/myEditText1" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:text=""
		android:singleLine="True" />
	<SurfaceView android:id="@+id/mSurfaceView1"
		android:visibility="visible" android:layout_width="320px"
		android:layout_height="240px">
	</SurfaceView>
	<LinearLayout android:orientation="horizontal" 
		android:layout_height="wrap_content" android:layout_width="fill_parent"
		android:padding="10dip">
		<ImageButton android:id="@+id/play" android:layout_height="wrap_content"
			android:layout_width="wrap_content" android:src="@drawable/play" />
		<ImageButton android:id="@+id/pause"
			android:layout_height="wrap_content" android:layout_width="wrap_content"
			android:src="@drawable/pause" />
		<ImageButton android:id="@+id/reset"
			android:layout_height="wrap_content" android:layout_width="wrap_content"
			android:src="@drawable/reset" />
		<ImageButton android:id="@+id/stop" android:layout_height="wrap_content"
			android:layout_width="wrap_content" android:src="@drawable/stop" />
	</LinearLayout>
</LinearLayout>

3.注意配置文件权限添加
<uses-permission android:name="android.permission.INTERNET">
	</uses-permission>


部分color.xml文件颜色初始化以及strings.xml中的我这里就不附上了
分享到:
评论

相关推荐

    神奇宝贝(PokemonGo)基于Jetpack+MVVM+Repository设计模式+Data.zip

    神奇宝贝(PokemonGo)基于Jetpack+MVVM+Repository设计模式+Data

    用于试用 Dev Containers 的 Python 示例项目.zip

    用于试用 Dev Containers 的 Python 示例项目试用开发容器Python开发容器是一个具有明确定义的工具/运行时堆栈及其先决条件的运行容器。您可以使用GitHub Codespaces或Visual Studio Code Dev Containers试用开发容器。这是一个示例项目,您可以通过几个简单的步骤尝试任一选项。我们还有各种其他vscode-remote-try-*示例项目。注意如果您已经有代码空间或开发容器,则可以跳至“要尝试的事情”部分。设置开发容器GitHub Codespaces请按照以下步骤在 Codespace 中打开此示例单击代码下拉菜单。单击Codespaces选项卡。单击主屏幕上的“创建代码空间”。有关创建代码空间的更多信息,请访问GitHub 文档。VS Code 开发容器如果您已安装 VS Code 和 Docker,则可以单击上方或此处的徽章开始使用。单击这些链接将导致 VS Code 根据需要自动安装 Dev Containers 扩展,将源代码克隆到容器卷中,并启动开发容器以供使用。按

    springboot vue3前后端分离.zip

    springboot vue3前后端分离

    数学建模-神经网络算法 lecture 11 线性随机系统辨识示例 共9页.pptx

    数学建模-神经网络算法 lecture 11 线性随机系统辨识示例 共9页.pptx

    优质粳稻生产技术规程.docx

    优质粳稻生产技术规程.docx

    所有算法均在 Python 3 中实现,是 hacktoberfest2020 的一个项目 - 没有针对 hacktoberfest 2021 的问题或 PR.zip

    算法 - Python 目录灵感与动力贡献指南从这里开始所有算法均用 Python 3 实现(用于教育)这些实现仅用于学习目的。如果您想贡献更有效的解决方案,请随时打开问题并提交您的解决方案。灵感你可以在LeetCode 算法中寻找要实现的算法若要贡献,请确保算法尚未提交!请确保在您的 PR 中添加问题编号。贡献指南文件夹和文件请确保你的文件位于 -Folder 中LeetCode,并且命名如下 0001_TwoSum.py-> LeetCode 问题的 4 位数字、下划线、LeetCodeName开放问题当您打开问题时,请确保问题尚未实现(查看代码/Leetcode 以获取问题编号)。现有问题打开的问题将被关闭,并且对此问题的 PR 被标记为垃圾邮件 。打开问题的贡献者将被优先分配到该问题。如果大约 7 天内没有 PR,则问题将分配给另一个贡献者。拉取请求只有与问题相结合并符合命名约定(参见文件夹和文件)的 Pull 请求才会被合并!如果 PR 中没有加入问题,您的 PR 将被标记为垃圾邮件并关闭。如果您的代码未通

    用于接收和交互来自 Slack 的 RTM API 的事件的框架.zip

    用于接收和交互来自 Slack 的 RTM API 的事件的框架python-rtmbot此项目不再处于积极开发阶段。如果您刚刚开始,我们建议您先查看Python SDK。如果您一直在使用此项目,我们只会解决关键问题(例如安全问题),但我们建议您计划迁移到 Python SDK。您仍然可以提交问题并向我们寻求帮助! 如果您有兴趣在未来维护此软件包,请联系我们 一个用 Python 编写的 Slack 机器人,通过 RTM API 连接。Python-rtmbot 是一个机器人引擎。任何了解Slack API和 Python的人都应该熟悉插件架构。配置文件格式为 YAML。该项目目前处于 1.0 之前的版本。因此,您应该计划不时进行重大更改。对于任何重大更改,我们将在 1.0 之前的版本中调整次要版本。(例如 0.2.4 -> 0.3.0 意味着重大更改)。如果稳定性很重要,您可能希望锁定特定的次要版本)与 webhook 的一些区别不需要网络服务器来接收消息可以回复用户的直接消息以 Slack 用户(或机器人)身份登录机器人用户必须被邀请加入频道

    基于django的音乐推荐系统.zip

    基于django的音乐推荐系统.zip

    北京理工大学<Python机器学习应用>超详细学习笔记和代码注释(未完待续).zip

    北京理工大学<Python机器学习应用>超详细学习笔记和代码注释(未完待续)

    kernel-5.15-rc7.zip

    kernel-5.15-rc7.zip

    神经网络-DenseNet网络结构

    神经网络-DenseNet网络结构

    rbac组件(基于角色的权限控制).zip

    rbac组件(基于角色的权限控制)

    C++ Vigenère 密码(解密代码)

    C++ Vigenère 密码(解密代码)

    数学建模培训资料 数学建模实战题目真题答案解析解题过程&论文报告 杭州消防设置-对杭州市消防局设置的研究 共8页.pdf

    数学建模培训资料 数学建模实战题目真题答案解析解题过程&论文报告 杭州消防设置-对杭州市消防局设置的研究 共8页.pdf

    老年用品产品推广目录分类表.docx

    老年用品产品推广目录分类表.docx

    毕设源码-基于Python的期货程序化交易系统的设计与实现_jhypi-期末大作业+说明文档.rar

    本项目是基于Python的期货程序化交易系统的设计与实现,旨在为计算机相关专业学生提供一个实践性强、贴近实际应用场景的项目案例。通过这一项目,学生们能够深入了解程序化交易的基本原理和实现方法,同时锻炼自身的编程技能、数据分析能力以及金融市场的洞察力。 项目的主要功能包括:自动收集和处理市场数据、基于预设策略进行交易决策、实时执行交易指令、监控交易风险以及生成详细的交易报告。系统采用模块化设计,主要包括数据采集模块、策略执行模块、交易执行模块和风险管理模块,各个模块之间通过明确的接口进行交互。项目采用的编程语言为Python,利用其强大的数据处理库和机器学习库,保证了系统的灵活性和扩展性。开发这一项目的目的是让学生们在实践中学习和掌握程序化交易的核心技术,提升其在金融科技领域的就业竞争力。

    基于java的校园失物招领平台设计与实现.docx

    基于java的校园失物招领平台设计与实现.docx

    Javascript Ninja 课程.zip

    Javascript Ninja 课程JavaScript Ninja 课程Inscreva-se agora mesmo e ganhe 10% de desconto!Como tirar dúvidas sobre 或 conteúdo do curso访问问题页面Pesquise nas发出abertas e fechadas, se a mesma dúvida já foi postadaSe não foi, crie uma nova issues , coloque um titulo que tenha a ver com a sua dúvida, e descreva-a com o maior nível detalhes possíveis, para que possamos te ajudar:)摘要Veja o sumário completo do curso aqui。赞同!:D

    通过示例在 Python 中解释 SOLID 原则 .zip

    solid.python通过示例在 Python 中解释SOLID 原则。单一职责原则开放/封闭原则里氏替换原则接口隔离原则依赖倒置原则

    公交信息在线查询系统 微信小程序+SSM毕业设计 源码+数据库+论文+启动教程.zip

    公交信息在线查询系统 微信小程序+SSM毕业设计 源码+数据库+论文+启动教程 项目启动教程:https://www.bilibili.com/video/BV1BfB2YYEnS

Global site tag (gtag.js) - Google Analytics