流媒体 播放 理论篇

流媒体播放

 

之所以为理论篇 因为该篇仅实现了播放功能 但还有一些其他待解决/完善功能 所以称之为理论篇

 

而且该篇以原理居多 故暂不释放源码

 

 

 

[原理]

写道
其实 原理很简单


1. 下载目标URI

2. 当下载了 96*10/8 Byte 开始播放之

3. 一边播放 一边下载

4. 当下载了 100 byte 暂停播放 重置播放目标 并继续播放

5. 下载完成后 重置播放目标 并继续播放

 

 

 

 

[代码 步骤]

 

1.  开辟Thread

 

public void startStreaming(final String mediaUri){
    	Runnable r = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try {
					readStream(mediaUri);
				} catch (MalformedURLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
    		
    	};
    	
    	new Thread(r).start();
    	
    }

 

 

 

2. 创建目标URI 并下载之

 

public void readStream(String mediaUri) throws MalformedURLException, IOException{
    	URLConnection uc = new URL(mediaUri).openConnection();
    	uc.connect();
    	
    	InputStream is = uc.getInputStream();
    	if(is == null){
    	//error, InputStream is null
    	}
    	
    	dlMedia = new File(context.getCacheDir(),"downloadingMedia.dat");
    	if(dlMedia.exists()){
    		dlMedia.delete();
    	}
    	
    	FileOutputStream fo = new FileOutputStream(dlMedia);
    	
    	byte buf[] = new byte[16384];
    	loadByte = 0;
    	
    	do {
    		int numread = is.read(buf); 
    		
    		loadByte += numread;
    		
    		if(numread <= 0){//end of stream, so exist
        		break;
        	}
    		
    		fo.write(buf, 0, numread);
    		
    		testMediaBuffer();
    	}
    	while(true);
    	is.close();
    	
    	//buffer all stream to MediaPlayer if end of stream
    	transferBufferToMediaPlayer();
    

 

 

 

3. 根据此刻下载的byte 判断是:开始播放 还是 缓冲下载数据

 

public void testMediaBuffer(){
    	Runnable update = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				//initial MediaPlayer if null
				if(mp == null){
					if(loadByte >= INTIAL_KB_BUFFER){
						loadByte = 0;
						
						startMediaPlayer();
					}
				}//load buffer while 1000
				else if(loadByte > BUFFER_KEY_BYTE) {
					
					loadByte = 0;
					transferBufferToMediaPlayer();
				}
			}
    		
    	};
    	
    	handler.post(update);
    }

 

 

 

4. 开始播放 并跟踪播放进度

 

public void startPlayProgressUpdater() {
    	//float progress = mp.getCurrentPosition();
    	
    	if (mp.isPlaying()) {
    		Runnable notification = new Runnable() {
    	        public void run() {
    	        	startPlayProgressUpdater();
    			}
    	    };
    	    handler.postDelayed(notification,100);
    	}
    }
    
    public void startMediaPlayer() {
        try {   
        	File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");
        	
        	// We double buffer the data to avoid potential read/write errors that could happen if the 
        	// download thread attempted to write at the same time the MediaPlayer was trying to read.
        	// For example, we can't guarantee that the MediaPlayer won't open a file for playing and leave it locked while 
        	// the media is playing.  This would permanently deadlock the file download.  To avoid such a deadloack, 
        	// we move the currently loaded data to a temporary buffer file that we start playing while the remaining 
        	// data downloads.  
        	moveFile(dlMedia,bufferedFile);

        	mp = createMediaPlayer(bufferedFile);
        	
    		// We have pre-loaded enough content and started the MediaPlayer so update the buttons & progress meters.
        	mp.start();
        	
        	startPlayProgressUpdater();
        } catch (IOException e) {
        	//Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);
        	return;
        }   
    }

 

 

 

5. 缓冲下载数据

 

private void transferBufferToMediaPlayer() {
        try {
        	//remember current position 
        	int curPosition = mp.getCurrentPosition();
        	
        	// Copy the currently downloaded content to a new buffered File.  Store the old File for deleting later. 
        	File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");

        	moveFile(dlMedia,bufferedFile);
        	
        	// Pause the current player now as we are about to create and start a new one.  So far (Android v1.5),
        	// this always happens so quickly that the user never realized we've stopped the player and started a new one
        	mp.pause();
        	
        	// Create a new MediaPlayer rather than try to re-prepare the prior one.
        	mp = createMediaPlayer(bufferedFile);
    		mp.seekTo(curPosition);

    		mp.start();
    		
        	// Lastly delete the previously playing buffered File as it's no longer needed.
        	bufferedFile.delete();
        	
        }catch (Exception e) {
        //error, to print
    	}
    }

 

 

6. 文件移动

 

private void moveFile(File oldLocation, File	newLocation)
    throws IOException {

    	if ( oldLocation.exists( )) {
    		BufferedInputStream  reader = new BufferedInputStream( new FileInputStream(oldLocation) );
    		BufferedOutputStream  writer = new BufferedOutputStream( new FileOutputStream(newLocation, false));
            try {
    	        byte[]  buff = new byte[8192];
    	        int numChars;
    	        while ( (numChars = reader.read(  buff, 0, buff.length ) ) != -1) {
    	        	writer.write( buff, 0, numChars );
      		    }
            } catch( IOException ex ) {
    			throw new IOException("IOException when transferring " + oldLocation.getPath() + " to " + newLocation.getPath());
            } finally {
                try {
                    if ( reader != null ){                    	
                    	writer.close();
                        reader.close();
                    }
                } catch( IOException ex ){
    			    //Log.e(getClass().getName(),"Error closing files when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() ); 
    			}
            }
        } else {
    		throw new IOException("Old location does not exist when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
        }
    }

 

 

 

7. 播放指定目标

 

private MediaPlayer createMediaPlayer(File mediaFile)
    throws IOException {
    	MediaPlayer mPlayer = new MediaPlayer();

    	//  It appears that for security/permission reasons, it is better to pass a FileDescriptor rather than a direct path to the File.
    	//  Also I have seen errors such as "PVMFErrNotSupported" and "Prepare failed.: status=0x1" if a file path String is passed to
    	//  setDataSource().  So unless otherwise noted, we use a FileDescriptor here.
    	FileInputStream fis = new FileInputStream(mediaFile);
    	mPlayer.setDataSource(fis.getFD());
    	mPlayer.prepare();
    	return mPlayer;
    }
 

 

8. Toast 信息提示:

 

public void popMsg(String msg){
    	Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
    }

 

 

9. done, plx test it, post feedback, thanks

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值