玩转 Android MediaPlayer之Media Proxy

article/2025/10/1 23:01:30

本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!

       本文是在《Android MediaPlayer与Http Proxy结合之提高篇》基础上,进一步优化代理服务器,支持了Http的302、301重定向,获取Http Request和Http Response的文本内容。本文以视频播放结合Http Proxy,讲述MediaPlayer播放过程中的握手过程。

吐槽一下:用google搜索“代理服务器”无效,所以本文用Media Proxy,大家懂的......

先来看看本文程序运行的截屏动画:

再来看看程序运行时输出的Log信息.....这里是关键:

07-29 15:51:30.692: E/HttpGetProxy(449): ..........sckPlayer connected.......... MediaPlayer发出请求
07-29 15:51:30.692: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:30.692: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:30.692: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:30.692: E/to Media Server---->(449):

07-29 15:51:31.119: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:31.122: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:31.775: E/from Media Server---->(449): HTTP/1.1 200 OK

07-29 15:51:31.775: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:33 GMT

07-29 15:51:31.775: E/from Media Server---->(449): Server: Apache

07-29 15:51:31.775: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:31.775: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:31.775: E/from Media Server---->(449): Content-Length: 754777

07-29 15:51:31.775: E/from Media Server---->(449): Content-Type: video/3gpp


07-29 15:51:34.512: E/HttpGetProxy(449): ..........sckPlayer connected..........MediaPlayer发出请求
07-29 15:51:34.532: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:34.532: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:34.532: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:34.532: E/to Media Server---->(449): Range: bytes=720896-

07-29 15:51:34.532: E/to Media Server---->(449):

07-29 15:51:34.873: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:34.873: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:35.505: E/from Media Server---->(449): HTTP/1.1 206 Partial Content

07-29 15:51:35.505: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:36 GMT

07-29 15:51:35.505: E/from Media Server---->(449): Server: Apache

07-29 15:51:35.505: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:35.505: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:35.505: E/from Media Server---->(449): Content-Length: 33881

07-29 15:51:35.505: E/from Media Server---->(449): Content-Range: bytes 720896-754776/754777

07-29 15:51:35.505: E/from Media Server---->(449): Content-Type: video/3gpp
07-29 15:51:38.754: E/HttpGetProxy(449): ..........over..........


07-29 15:51:51.461: E/HttpGetProxy(449): ..........sckPlayer connected..........MediaPlayer发出请求
07-29 15:51:51.471: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:51.471: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:51.471: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:51.471: E/to Media Server---->(449): Range: bytes=196608-

07-29 15:51:51.471: E/to Media Server---->(449):

07-29 15:51:51.722: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:51.722: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:52.285: E/from Media Server---->(449): HTTP/1.1 206 Partial Content

07-29 15:51:52.285: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:53 GMT

07-29 15:51:52.285: E/from Media Server---->(449): Server: Apache

07-29 15:51:52.285: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:52.285: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:52.285: E/from Media Server---->(449): Content-Length: 558169

07-29 15:51:52.285: E/from Media Server---->(449): Content-Range: bytes 196608-754776/754777

07-29 15:51:52.285: E/from Media Server---->(449): Content-Type: video/3gpp


07-29 15:51:54.812: E/HttpGetProxy(449): ..........sckPlayer connected..........MediaPlayer发出请求
07-29 15:51:54.822: E/to Media Server---->(449): GET /vids/family_guy_penis_car.3gp HTTP/1.1

07-29 15:51:54.822: E/to Media Server---->(449): User-Agent: stagefright/1.0 (Linux;Android 2.2)

07-29 15:51:54.822: E/to Media Server---->(449): Host: daily3gp.com

07-29 15:51:54.822: E/to Media Server---->(449): Range: bytes=589824-

07-29 15:51:54.822: E/to Media Server---->(449):

07-29 15:51:55.117: E/HttpGetProxy(449): ..........remote Server connected..........
07-29 15:51:55.117: E/HttpGetProxy(449): ..........remote start to receive..........
07-29 15:51:55.693: E/from Media Server---->(449): HTTP/1.1 206 Partial Content

07-29 15:51:55.693: E/from Media Server---->(449): Date: Sun, 29 Jul 2012 15:51:57 GMT

07-29 15:51:55.693: E/from Media Server---->(449): Server: Apache

07-29 15:51:55.693: E/from Media Server---->(449): Last-Modified: Thu, 14 Jan 2010 23:29:02 GMT

07-29 15:51:55.693: E/from Media Server---->(449): Accept-Ranges: bytes

07-29 15:51:55.693: E/from Media Server---->(449): Content-Length: 164953

07-29 15:51:55.693: E/from Media Server---->(449): Content-Range: bytes 589824-754776/754777

07-29 15:51:55.693: E/from Media Server---->(449): Content-Type: video/3gpp
07-29 15:51:59.620: E/HttpGetProxy(449): ..........over..........

 

从截屏动画和Log信息看出,手动seek一次,但MediaPlayer进行了多次Range请求,这说明了“MediaPlayer会自动seek”,或许与MediaPlayer本地缓存有关。另外,不同硬解厂家实现的MediaPlayer估计会有不同的操作。

 

本文的代码可以到这里下载:

http://download.csdn.net/detail/hellogv/4463651

HttpGetProxy.JAVA还是本文的关键部分:

public class HttpGetProxy {  final static private String TAG = "HttpGetProxy";  final static private String LOCAL_IP_ADDRESS_1 = "127.0.0.1";final static private String LOCAL_IP_ADDRESS_2 = "10.0.2.2";final static private int HTTP_PORT = 80;final static private String HTTP_END="\r\n\r\n";/**代理服务器使用的端口*/private int proxy_ip_port;/**链接带的端口*/private String original_ip_port;/**远程服务器地址*/private String remoteHost;/**本地服务器地址*/private String localHost;private ServerSocket localServer = null;  /**收发Media Player请求的Socket*/private Socket sckPlayer = null;/**收发Media Server请求的Socket*/private Socket sckServer = null;private SocketAddress address;  /** * 初始化代理服务器 * @param localport 代理服务器监听的端口 */  public HttpGetProxy(int localport) {  try {_HttpGetProxy(LOCAL_IP_ADDRESS_1,localport);} catch (Exception e) {Log.e(TAG,LOCAL_IP_ADDRESS_1+"???"+e.toString());try {_HttpGetProxy(LOCAL_IP_ADDRESS_2,localport);}catch (Exception e1) {Log.e(TAG,LOCAL_IP_ADDRESS_2+"???"+e.toString());System.exit(0);}}}private void _HttpGetProxy(String ipAddress,int localport) throws UnknownHostException, IOException {  proxy_ip_port=localport;  localServer = new ServerSocket(localport,1,InetAddress.getByName(ipAddress));localHost=ipAddress;}/** * 把网络URL转为本地URL,127.0.0.1替换网络域名 * @param url 网络URL  * @return 本地URL */  public String getLocalURL(String urlString){//----排除HTTP特殊----//String targetUrl=ProxyUtils.getRedirectUrl(urlString);//----获取对应本地代理服务器的链接----//String result = null;URI originalURI=URI.create(targetUrl);  remoteHost=originalURI.getHost();  if(originalURI.getPort()!=-1){//URL带Portaddress = new InetSocketAddress(remoteHost,originalURI.getPort());//使用默认端口  original_ip_port = originalURI.getPort()+"";//保存端口,中转时替换result=targetUrl.replace(remoteHost+":"+originalURI.getPort(),  localHost+":"+proxy_ip_port);  }  else{//URL不带Port  address = new InetSocketAddress(remoteHost,HTTP_PORT);//使用80端口 original_ip_port = "";result=targetUrl.replace(remoteHost,localHost+":"+proxy_ip_port);  }return result;     }  /** * 启动代理服务器 * @throws IOException */  public void asynStartProxy(){  new Thread() {  public void run() {int bytes_read;  byte[] local_request = new byte[1024];  byte[] remote_reply = new byte[1024];  while (true) {  try {  //--------------------------------------  //监听MediaPlayer的请求,MediaPlayer->代理服务器  //--------------------------------------  sckPlayer = localServer.accept();  Log.e(TAG, "..........sckPlayer connected..........");   String requestStr = "";while ((bytes_read = sckPlayer.getInputStream().read(local_request)) != -1) {byte[] tmpBuffer=new byte[bytes_read]; System.arraycopy(local_request,0,tmpBuffer,0,bytes_read);String str = new String(tmpBuffer);//Log.e("from MediaPlayer---->", str);  requestStr = requestStr + str;  if (requestStr.contains("GET")  && requestStr.contains(HTTP_END)) {  break;}   }//把request中的本地ip改为远程iprequestStr = requestStr.replace(localHost,remoteHost);//把代理服务器端口改为原URL端口if(TextUtils.isEmpty(original_ip_port))requestStr = requestStr.replace(":"+proxy_ip_port, "");elserequestStr = requestStr.replace(":"+proxy_ip_port, ":"+original_ip_port);Log.e("to Media Server---->", requestStr);//--------------------------------------  //把MediaPlayer的请求发到网络服务器,代理服务器->网络服务器  //--------------------------------------sckServer = new Socket();  sckServer.connect(address);  Log.e(TAG,"..........remote Server connected..........");  sckServer.getOutputStream().write(requestStr.getBytes());//发送MediaPlayer的请求  //------------------------------------------------------  //把网络服务器的反馈发到MediaPlayer,网络服务器->代理服务器->MediaPlayer  //------------------------------------------------------Log.e(TAG,"..........remote start to receive..........");String responseStr = "";boolean isCaptured=false;while ((bytes_read = sckServer.getInputStream().read(remote_reply)) != -1) {byte[] tmpBuffer=new   byte[bytes_read]; System.arraycopy(remote_reply,0,tmpBuffer,0,bytes_read);//----捕获收到的Response文本内容----//if (!isCaptured) {String str = new String(tmpBuffer);responseStr += str;if (responseStr.contains("HTTP/")  && responseStr.contains(HTTP_END)) {int endIndex=responseStr.indexOf(HTTP_END, 0);responseStr=responseStr.substring(0, endIndex);Log.e("from Media Server---->", responseStr);isCaptured=true;}}sckPlayer.getOutputStream().write(tmpBuffer);  sckPlayer.getOutputStream().flush();}Log.e(TAG, "..........over.........."); //关闭对内,对内 2个SOCKETsckPlayer.close();  sckServer.close();  } catch (IOException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  }  }.start();  }  
}  



http://chatgpt.dhexx.cn/article/roD6L4yv.shtml

相关文章

MediaPlayer播放assets文件夹下的音频

一、先放张图,MediaPlayer的生命周期图如下: 二、mediaPlayer方法 setDataSource() //设置要播放的音频文件的位置 prepare() //在开始播放之前调用这个方法完成准备工作 start() //开始或继续播放音频 pause() //暂停播放音频 reset() //将MediaPlayer…

Android openGL+MediaPlayer播放视频

在Android平台折腾了好多次openGL MediaPlayer播放视频的事情,openGL本身是套API规范,其身后的计算机图形学还是比较难缠,但只是播放视频用不了太多东西,没有过多的坐标转换、简单2D纹理展示,实现起来还是比较简单&am…

Android-MediaPlayer播放网络音频

官方文档&#xff1a;https://developer.android.google.cn/reference/android/media/MediaPlayer 运行截图&#xff1a; 主布局文件&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.a…

深入Android MediaPlayer的使用方法详解

1&#xff09;如何获得MediaPlayer实例&#xff1a; 可以使用直接new的方式&#xff1a; MediaPlayer mp new MediaPlayer(); 也可以使用create的方式&#xff0c;如&#xff1a; MediaPlayer mp MediaPlayer.create(this, R.raw.test);//这时就不用调用setDataSource了 2) 如…

Android MediaPlayer状态机

翻译Android Reference Manual的MediaPlayer的状态机 对播放音频/视频文件和流的控制是通过一个状态机来管理的。下图显示一个MediaPlayer对象被支持的播放控制操作驱动的生命周期和状态。椭圆代表MediaPlayer对象可能驻留的状态。弧线表示驱动MediaPlayer在各个状态之间迁移的…

Android提高第二十一篇之MediaPlayer播放网络视频

本文来自http://blog.csdn.net/hellogv/ &#xff0c;引用必须注明出处&#xff01; 上次讲解了MediaPlayer播放网络音频&#xff0c;介绍了MediaPlayer关于网络音频的缓冲和进度条控制的方法&#xff0c;这次再讲解MediaPlayer播放网络视频。播放网络视频比播放网络音频多需要…

Android开发之MediaPlayer详解

Android开发之MdiaPlayer详解 MediaPlayer类可用于控制音频/视频文件或流的播放&#xff0c;我曾在《Android开发之基于Service的音乐播放器》一文中介绍过它的使用。下面让我们看一下MediaPlayer类的详细介绍。 一、类结构&#xff1a; java.lang.Object ↳ android.med…

Android 9.0 MediaPlayer播放流程分析

1.MediaPlayer初始化流程 EventHandler是后面处理数据回调的handler. 在AudioFlinger.cpp中获取nextUniqueId&#xff1a; audio_unique_id_t AudioFlinger::nextUniqueId(audio_unique_id_use_t use) {// This is the internal API, so it is OK to assert on bad parameter.…

Android的MediaPlayer架构介绍

本文主要介绍的是Android中很重要也最为复杂的媒体播放器&#xff08;MediaPlayer&#xff09;部分的架构。对于Android这样一个完整又相对复杂的系统&#xff0c;一个MediaPlayer功能的实现不在其具体的功能&#xff0c;而是具体功能如何适应Android系统Android MediaPlayer的…

Android之MediaPlayer详解

文章转自&#xff1a;http://www.cnblogs.com/gansc23/archive/2011/04/08/2009868.html MediaPlayer类可用于控制音频/视频文件或流的播放。关于如何使用这个类的方法还可以阅读VideoView类的文档。 1&#xff0e;状态图 对播放音频/视频文件和流的控制是通过一个状态机来…

Android MediaPlayer播放视频详细步骤

MediaPlayer类是媒体框架最重要的组成部分之一&#xff0c;此类的对象能够获取&#xff0c;解码以及播放音频和视频&#xff0c;而且只需极少量设置&#xff0c;它支持多种不同的媒体源&#xff0c;例如&#xff1a; 本地资源 内部Url&#xff0c;例如您可能从内容解析器获取U…

Android MediaPlayer

最近在做游戏状态的保存时&#xff0c;需要存储背景音乐是否静音了&#xff0c;一直不成功&#xff0c;并且总是报出如下错误&#xff1a; ERROR/MediaPlayer(9974): start called in state 64 ERROR/MediaPlayer(9974): error (-38, 0) ERROR/MediaPlayer(9974): Error (-38…

MediaPlayer类播放音频

一、MediaPlayer类 1、常用方法 方法名称功能setDataSource()设置要播放的音频文件prepare()在开始播放前。调用该方法准备播放start()开始播放或者继续播放音频pause()暂停播放reset()重置MediaPlayer对象seekTo()从指定位置播放stop()停止播放&#xff0c;调用后MediaPlaye…

Android提高第一篇之MediaPlayer

本文来自http://blog.csdn.net/hellogv/ &#xff0c;引用必须注明出处&#xff01; 前面写了十四篇关于界面的入门文章&#xff0c;大家都看完和跟着练习之后&#xff0c;对于常用的Layout和View都会有一定的了解了,接下来的文章就不再强调介绍界面了&#xff0c;而是针对具体…

Android中的MediaPlayer的使用详解

今天本文介绍的是Andriod系统自带的Mediaplayer,和VideoView实现简单的音乐和视频的播放&#xff0c;至于想做出如酷狗音乐这样的APP的话&#xff0c;只要想做&#xff0c;应该也不难&#xff0c;都是基于此实现了功能的扩展。 Android的MediaPlayer包含了Audio和Video的播放功…

MediaPlayer详解和使用

Android多媒体相关的API&#xff0c;网上基本都能找到很多相关的文章&#xff0c;使用起来也很简单&#xff0c;一直在犹豫要不要写这方面的内容&#xff0c;后来决定还是写一写&#xff0c;一方面算是一个归纳总结&#xff0c;另一方面&#xff0c;也方便以后查阅。这一篇就写…

MediaPlayer的使用

MediaPlayer的使用 MediaPlayer的使用&#xff08;2019.07.16&#xff09;1.视频播放器的原理2.Android系统自带的MediaPlay状态机详解&#xff08;MediaPlay的生命周期&#xff09;3.如何使用MediaPlayer播放音频与视频&#xff08;一 &#xff09;播放音频&#xff08;二&…

MediaPlayer使用以及常见问题

前面已经写过一篇类似的文章&#xff0c;但是还不够细致&#xff1a; 采用Android的MediaPlayerSurfaceView设计视频播放器 这里我们重新理一下&#xff0c;并记录一点实际运用时遇到的问题。 MediaPlayer特性 MediaPlayer类用于控制音频文件、视频文件和流的播放。 Media…

Android MediaPlayer类

1. MediaPlayer方法 MediaPlayer创建 可以直接调用构造函数&#xff0c;利用setDataSource()方法设置资源。MediaPlayer mp new MediaPlayer(); // path可以是本地路径&#xff0c;也可以是网络地址 mp.setDataSource(String path);也可以调用create()方法&#xff0c;create…

MediaPlayer状态图及生命周期

MediaPlayer状态图及生命周期 MediaPlayer是Android中的uoge多媒体播放类&#xff0c;我们能通过它控制音视频流或本地音视频资源的播放过程。 这一片博客主要介绍MediaPlayer状态图及生命周期。先看一张官网很经典的MediaPlayer状态机的图片。 其中椭圆代表MediaPlayer驻留…