我正在使用此代码但是当我尝试在下载视频期间播放视频时,video_view显示我无法播放视频
private String videoPath="http://codechair.com/video/1496139752333.mp4";
private String outFilePath="/sdcard/file_name_soniji.mp4";
//My Mobile Ip
private String serverPath="10.92.234.117";
private VideoDownloadAndPlayService videoService;
public class Testing extends AppCompatActivity {
VideoView videoView;
MediaController mediaController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_testing);
videoView = (VideoView) findViewById(R.id.vid258);
mediaController = new MediaController(this);
startServer();
}
private void startServer()
{
videoService = VideoDownloadAndPlayService.startServer(Testing.this, videoPath,outFilePath, serverPath, new VideoDownloadAndPlayService.VideoStreamInterface()
{
@Override
public void onServerStart(String videoStreamUrl)
{
// try to play
videoView.setVideoPath(outFilePath);
videoView.requestFocus();
videoView.setMediaController(mediaController);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//mp.setLooping(true);
videoView.start();
}
});
// use videoStreamUrl to play video through media player
}
});
}
和VideoDownloadAndPlayService在这里
public class VideoDownloadAndPlayService
{
final static String TAG="VideoDown";
private static LocalFileStreamingServer server;
public VideoDownloadAndPlayService(LocalFileStreamingServer server)
{
this.server = server;
}
public static VideoDownloadAndPlayService startServer(final Activity activity, String videoUrl, String pathToSaveVideo, final String ipOfServer, final VideoStreamInterface callback)
{
new VideoDownloader().execute(videoUrl, pathToSaveVideo);
server = new LocalFileStreamingServer(new File(pathToSaveVideo));
server.setSupportPlayWhileDownloading(true);
new Thread(new Runnable()
{
@Override
public void run()
{
server.init(ipOfServer);
activity.runOnUiThread(new Runnable()
{
@Override
public void run()
{
// Log.d(TAG,"videourl "+String.valueOf(videoUrl));
server.start();
callback.onServerStart(server.getFileUrl());
}
});
}
}).start();
return new VideoDownloadAndPlayService(server);
}
public void start(){
server.start();
}
public void stop(){
server.stop();
}
public static interface VideoStreamInterface{
public void onServerStart(String videoStreamUrl);
}
}
LocalFileStreamingServer类文件在这里
public class LocalFileStreamingServer implements Runnable
{
private static final String TAG = LocalFileStreamingServer.class.getName();
private int port = 0;
private boolean isRunning = false;
private ServerSocket socket;
private Thread thread;
private long cbSkip;
private boolean seekRequest;
private File mMovieFile;
private boolean supportPlayWhileDownloading = false;
/**
* This server accepts HTTP request and returns files from device.
*/
public LocalFileStreamingServer(File file)
{
mMovieFile = file;
}
/**
* @return A port number assigned by the OS.
*/
public int getPort()
{
return port;
}
/**
* Prepare the server to start.
* <p>
* This only needs to be called once per instance. Once initialized, the
* server can be started and stopped as needed.
*/
public String init(String ip)
{
String url = null;
try
{
InetAddress inet = InetAddress.getByName(ip);
byte[] bytes = inet.getAddress();
socket = new ServerSocket(port, 0, InetAddress.getByAddress(bytes));
socket.setSoTimeout(10000);
port = socket.getLocalPort();
url = "http://" + socket.getInetAddress().getHostAddress() + ":"
+ port;
Log.e(TAG, "Server started at " + url);
} catch (UnknownHostException e)
{
Log.e(TAG, "Error UnknownHostException server", e);
} catch (IOException e)
{
Log.e(TAG, "Error IOException server", e);
}
return url;
}
public String getFileUrl()
{
return "http://" + socket.getInetAddress().getHostAddress() + ":"
+ port + "/" + mMovieFile.getName();
}
/**
* Start the server.
*/
public void start()
{
thread = new Thread(this);
thread.start();
isRunning = true;
}
/**
* Stop the server.
* <p>
* This stops the thread listening to the port. It may take up to five
* seconds to close the service and this call blocks until that occurs.
*/
public void stop()
{
isRunning = false;
if (thread == null)
{
Log.e(TAG, "Server was stopped without being started.");
return;
}
Log.e(TAG, "Stopping server.");
thread.interrupt();
}
/**
* Determines if the server is running (i.e. has been <code>start</code>ed
* and has not been <code>stop</code>ed.
*
* @return <code>true</code> if the server is running, otherwise
* <code>false</code>
*/
public boolean isRunning()
{
return isRunning;
}
/**
* This is used internally by the server and should not be called directly.
*/
@Override
public void run()
{
Log.e(TAG, "running");
while (isRunning)
{
try
{
Socket client = socket.accept();
if (client == null)
{
continue;
}
Log.e(TAG, "client connected at " + port);
ExternalResourceDataSource data = new ExternalResourceDataSource(
mMovieFile);
Log.e(TAG, "processing request...");
processRequest(data, client);
} catch (SocketTimeoutException e)
{
Log.e(TAG, "No client connected, waiting for client...", e);
// Do nothing
} catch (IOException e)
{
Log.e(TAG, "Error connecting to client", e);
// break;
}
}
Log.e(TAG, "Server interrupted or stopped. Shutting down.");
}
/**
* Find byte index separating header from body. It must be the last byte of
* the first two sequential new lines.
**/
private int findHeaderEnd(final byte[] buf, int rlen)
{
int splitbyte = 0;
while (splitbyte + 3 < rlen)
{
if (buf[splitbyte] == '\r' && buf[splitbyte + 1] == '\n'
&& buf[splitbyte + 2] == '\r' && buf[splitbyte + 3] == '\n')
return splitbyte + 4;
splitbyte++;
}
return 0;
}
/*
* Sends the HTTP response to the client, including headers (as applicable)
* and content.
*/
private void processRequest(ExternalResourceDataSource dataSource,
Socket client) throws IllegalStateException, IOException
{
if (dataSource == null)
{
Log.e(TAG, "Invalid (null) resource.");
client.close();
return;
}
InputStream is = client.getInputStream();
final int bufsize = 8192;
byte[] buf = new byte[bufsize];
int splitbyte = 0;
int rlen = 0;
{
int read = is.read(buf, 0, bufsize);
while (read > 0)
{
rlen += read;
splitbyte = findHeaderEnd(buf, rlen);
if (splitbyte > 0)
break;
read = is.read(buf, rlen, bufsize - rlen);
}
}
// Create a BufferedReader for parsing the header.
ByteArrayInputStream hbis = new ByteArrayInputStream(buf, 0, rlen);
BufferedReader hin = new BufferedReader(new InputStreamReader(hbis));
Properties pre = new Properties();
Properties parms = new Properties();
Properties header = new Properties();
try
{
decodeHeader(hin, pre, parms, header);
} catch (InterruptedException e1)
{
Log.e(TAG, "Exception: " + e1.getMessage());
e1.printStackTrace();
}
for (Entry<Object, Object> e : header.entrySet())
{
Log.e(TAG, "Header: " + e.getKey() + " : " + e.getValue());
}
String range = header.getProperty("range");
cbSkip = 0;
seekRequest = false;
if (range != null)
{
Log.e(TAG, "range is: " + range);
seekRequest = true;
range = range.substring(6);
int charPos = range.indexOf('-');
if (charPos > 0)
{
range = range.substring(0, charPos);
}
cbSkip = Long.parseLong(range);
Log.e(TAG, "range found!! " + cbSkip);
}
String headers = "";
// Log.e(TAG, "is seek request: " + seekRequest);
if (seekRequest)
{// It is a seek or skip request if there's a Range
// header
headers += "HTTP/1.1 206 Partial Content\r\n";
headers += "Content-Type: " + dataSource.getContentType() + "\r\n";
headers += "Accept-Ranges: bytes\r\n";
headers += "Content-Length: " + dataSource.getContentLength(false)
+ "\r\n";
headers += "Content-Range: bytes " + cbSkip + "-"
+ dataSource.getContentLength(true) + "/*\r\n";
headers += "\r\n";
} else
{
headers += "HTTP/1.1 200 OK\r\n";
headers += "Content-Type: " + dataSource.getContentType() + "\r\n";
headers += "Accept-Ranges: bytes\r\n";
headers += "Content-Length: " + dataSource.getContentLength(false)
+ "\r\n";
headers += "\r\n";
}
InputStream data = null;
try
{
data = dataSource.createInputStream();
byte[] buffer = headers.getBytes();
Log.e(TAG, "writing to client");
client.getOutputStream().write(buffer, 0, buffer.length);
// Start sending content.
byte[] buff = new byte[1024 * 50];
Log.e(TAG, "No of bytes skipped: " + data.skip(cbSkip));
int cbSentThisBatch = 0;
while (isRunning)
{
if (supportPlayWhileDownloading)
{
// Check if data is ready
while (!VideoDownloader.isDataReady())
{
if (VideoDownloader.dataStatus == VideoDownloader.DATA_READY)
{
Log.e(TAG, "error in reading bytess**********(Data ready)");
break;
} else if (VideoDownloader.dataStatus == VideoDownloader.DATA_CONSUMED)
{
Log.e(TAG, "error in reading bytess**********(All Data consumed)");
break;
} else if (VideoDownloader.dataStatus == VideoDownloader.DATA_NOT_READY)
{
Log.e(TAG, "error in reading bytess**********(Data not ready)");
} else if (VideoDownloader.dataStatus == VideoDownloader.DATA_NOT_AVAILABLE)
{
Log.e(TAG, "error in reading bytess**********(Data not available)");
}
// wait for a second if data is not ready
synchronized (this)
{
Thread.sleep(1000);
}
}
Log.e(TAG, "error in reading bytess**********(Data ready)");
}
int cbRead = data.read(buff, 0, buff.length);
if (cbRead == -1)
{
Log.e(TAG,
"readybytes are -1 and this is simulate streaming, close the ips and create another ");
data.close();
data = dataSource.createInputStream();
cbRead = data.read(buff, 0, buff.length);
if (cbRead == -1)
{
Log.e(TAG, "error in reading bytess**********");
throw new IOException(
"Error re-opening data source for looping.");
}
}
client.getOutputStream().write(buff, 0, cbRead);
client.getOutputStream().flush();
cbSkip += cbRead;
cbSentThisBatch += cbRead;
if(supportPlayWhileDownloading)
VideoDownloader.consumedb += cbRead;
}
Log.e(TAG, "cbSentThisBatch: " + cbSentThisBatch);
// If we did nothing this batch, block for a second
if (cbSentThisBatch == 0)
{
Log.e(TAG, "Blocking until more data appears");
Thread.sleep(1000);
}
} catch (SocketException e)
{
// Ignore when the client breaks connection
Log.e(TAG, "Ignoring " + e.getMessage());
} catch (IOException e)
{
Log.e(TAG, "Error getting content stream.", e);
} catch (Exception e)
{
Log.e(TAG, "Error streaming file content.", e);
} finally
{
if (data != null)
{
data.close();
}
client.close();
}
}
/**
* Decodes the sent headers and loads the data into java Properties' key -
* value pairs
**/
private void decodeHeader(BufferedReader in, Properties pre,
Properties parms, Properties header) throws InterruptedException
{
try
{
// Read the request line
String inLine = in.readLine();
if (inLine == null)
return;
StringTokenizer st = new StringTokenizer(inLine);
if (!st.hasMoreTokens())
Log.e(TAG,
"BAD REQUEST: Syntax error. Usage: GET /example/file.html");
String method = st.nextToken();
pre.put("method", method);
if (!st.hasMoreTokens())
Log.e(TAG,
"BAD REQUEST: Missing URI. Usage: GET /example/file.html");
String uri = st.nextToken();
// Decode parameters from the URI
int qmi = uri.indexOf('?');
if (qmi >= 0)
{
decodeParms(uri.substring(qmi + 1), parms);
uri = decodePercent(uri.substring(0, qmi));
} else
uri = decodePercent(uri);
// If there's another token, it's protocol version,
// followed by HTTP headers. Ignore version but parse headers.
// NOTE: this now forces header names lowercase since they are
// case insensitive and vary by client.
if (st.hasMoreTokens())
{
String line = in.readLine();
while (line != null && line.trim().length() > 0)
{
int p = line.indexOf(':');
if (p >= 0)
header.put(line.substring(0, p).trim().toLowerCase(),
line.substring(p + 1).trim());
line = in.readLine();
}
}
pre.put("uri", uri);
} catch (IOException ioe)
{
Log.e(TAG,
"SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
}
}
/**
* Decodes parameters in percent-encoded URI-format ( e.g.
* "name=Jack%20Daniels&pass=Single%20Malt" ) and adds them to given
* Properties. NOTE: this doesn't support multiple identical keys due to the
* simplicity of Properties -- if you need multiples, you might want to
* replace the Properties with a Hashtable of Vectors or such.
*/
private void decodeParms(String parms, Properties p)
throws InterruptedException
{
if (parms == null)
return;
StringTokenizer st = new StringTokenizer(parms, "&");
while (st.hasMoreTokens())
{
String e = st.nextToken();
int sep = e.indexOf('=');
if (sep >= 0)
p.put(decodePercent(e.substring(0, sep)).trim(),
decodePercent(e.substring(sep + 1)));
}
}
/**
* Decodes the percent encoding scheme. <br/>
* For example: "an+example%20string" -> "an example string"
*/
private String decodePercent(String str) throws InterruptedException
{
try
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
switch (c)
{
case '+':
sb.append(' ');
break;
case '%':
sb.append((char) Integer.parseInt(
str.substring(i + 1, i + 3), 16));
i += 2;
break;
default:
sb.append(c);
break;
}
}
return sb.toString();
} catch (Exception e)
{
Log.e(TAG, "BAD REQUEST: Bad percent-encoding.");
return null;
}
}
public boolean isSupportPlayWhileDownloading()
{
return supportPlayWhileDownloading;
}
public void setSupportPlayWhileDownloading(boolean supportPlayWhileDownloading)
{
this.supportPlayWhileDownloading = supportPlayWhileDownloading;
}
/**
* provides meta-data and access to a stream for resources on SD card.
*/
protected class ExternalResourceDataSource
{
private final File movieResource;
long contentLength;
private FileInputStream inputStream;
public ExternalResourceDataSource(File resource)
{
movieResource = resource;
Log.e(TAG, "respurcePath is: " + mMovieFile.getPath());
}
/**
* Returns a MIME-compatible content type (e.g. "text/html") for the
* resource. This method must be implemented.
*
* @return A MIME content type.
*/
public String getContentType()
{
// TODO: Support other media if we need to
return "video/mp4";
}
/**
* Creates and opens an input stream that returns the contents of the
* resource. This method must be implemented.
*
* @return An <code>InputStream</code> to access the resource.
* @throws IOException If the implementing class produces an error when opening
* the stream.
*/
public InputStream createInputStream() throws IOException
{
// NB: Because createInputStream can only be called once per asset
// we always create a new file descriptor here.
getInputStream();
return inputStream;
}
/**
* Returns the length of resource in bytes.
* <p>
* By default this returns -1, which causes no content-type header to be
* sent to the client. This would make sense for a stream content of
* unknown or undefined length. If your resource has a defined length
* you should override this method and return that.
*
* @return The length of the resource in bytes.
*/
public long getContentLength(boolean ignoreSimulation)
{
if (!ignoreSimulation)
{
return -1;
}
return contentLength;
}
private void getInputStream()
{
try
{
inputStream = new FileInputStream(movieResource);
} catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
// File temp = new File(respurcePath);
contentLength = movieResource.length();
Log.e(TAG, "file exists??" + movieResource.exists()
+ " and content length is: " + contentLength);
}
}
}
最后一个VideoDownloader文件在这里
public class VideoDownloader extends AsyncTask<String, Integer, Void>
{
public static final int DATA_READY = 1;
public static final int DATA_NOT_READY = 2;
public static final int DATA_CONSUMED = 3;
public static final int DATA_NOT_AVAILABLE = 4;
public static int dataStatus = -1;
public static boolean isDataReady(){
dataStatus = -1;
boolean res = false;
if(fileLength == readb){
dataStatus = DATA_CONSUMED;
res = false;
}else if(readb > consumedb){
dataStatus = DATA_READY;
res = true;
}else if(readb <= consumedb){
dataStatus = DATA_NOT_READY;
res = false;
}else if(fileLength == -1){
dataStatus = DATA_NOT_AVAILABLE;
res = false;
}
return res;
}
/**
* Keeps track of read bytes while serving to video player client from server
*/
public static int consumedb = 0;
/**
* Keeps track of all bytes read on each while iteration
*/
private static int readb = 0;
/**
* Length of file being downloaded.
*/
static int fileLength = -1;
@Override
protected Void doInBackground(String... params)
{
BufferedInputStream input = null;
try
{
final FileOutputStream out = new FileOutputStream(params[1]);
try
{
URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
{
throw new RuntimeException("response is not http_ok");
}
fileLength = connection.getContentLength();
input = new BufferedInputStream(connection.getInputStream());
byte data[] = new byte[1024 * 50];
long readBytes = 0;
int len;
boolean flag = true;
while ((len = input.read(data)) != -1)
{
out.write(data, 0, len);
out.flush();
readBytes += len;
readb += len;
Log.w("download", (readb / 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");
}
}
答案 0 :(得分:0)
您拥有以下权限吗?
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
您还需要向用户请求权限:
public static final int REQUEST_EXTERNAL_PERMISSION_CODE = 666;
public static final String[] PERMISSIONS_EXTERNAL_STORAGE = {
READ_EXTERNAL_STORAGE,
WRITE_EXTERNAL_STORAGE
};
public boolean checkExternalStoragePermission(Activity activity) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
return true;
}
int readStoragePermissionState = ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
int writeStoragePermissionState = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
boolean externalStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED &&
writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
if (!externalStoragePermissionGranted) {
requestPermissions(PERMISSIONS_EXTERNAL_STORAGE, REQUEST_EXTERNAL_PERMISSION_CODE);
}
return externalStoragePermissionGranted;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestCode == REQUEST_EXTERNAL_PERMISSION_CODE) {
if (checkExternalStoragePermission(this)) {
// Continue with your action after permission request succeed
}
}
}
}
并加入onCreate:
checkExternalStoragePermission(this);