Get length of data from inputstream opened by content-resolver - inputstream

I am doing video (and also photo) uploading to the server by using HttpURLConnection.
I have an Uri of a video. I open an InputStream this way:
InputStream inputStream = context.getContentResolver().openInputStream(uri);
As video file is pretty big, I can't buffer data while writing it into the outputStream. So I need to use setFixedLengthStreamingMode(contentLength) method of HttpURLConnection. But it requires "contentLength".
The question is, how to get the length of the video?
Please don't suggest getting filepath. On some devices it works, but it often fails (especially on Android 6). They say Uri doesn't necessarily represent a file.
I also stumbled onto situations when after opening device gallery (with Intent) I receive an Uri of a picture, but I fail trying to get filepath from it. So I believe it's not a good way to get filepath from Uri?

Try something like this:
void uploadVideo() {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
// Your connection.
HttpURLConnection connection;
// Do connection setup, setDoOutput etc.
// Be sure that the server is able to handle
// chunked transfer encoding.
connection.setChunkedStreamingMode(0);
OutputStream connectionOs = connection.getOutputStream();
// Read and write a 4 KiB chunk a time.
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
connectionOs.write(buffer, 0, bytesRead);
}
// Close streams, do connection etc.
}
UPDATE: added setChunkedStreamingMode

Related

Is there a cross-platform solution to ImageSource to byte[]?

I did researches and fell on this solution: http://forums.xamarin.com/discussion/22682/is-there-a-way-to-turn-an-imagesource-into-a-byte-array
Initial question: http://forums.xamarin.com/discussion/29569/is-there-a-cross-platform-solution-to-imagesource-to-byte#latest
We want to upload an image through a HTTP Post, here's what we tried:
HttpClient httpClient = new HttpClient ();
byte[] TargetImageByte = **TargetImageSource**; //How to convert it to a byte[]?
HttpContent httpContent = new ByteArrayContent (TargetImageByte);
httpClient.PostAsync ("https://api.magikweb.ca/debug/file.php", httpContent);
We also are having a hard time with the libraries we gotta include in the using clauses. It seems like using System.IO; works, but it doesn't give us access to classes like FileInfo or FileStream.
Anybody has any idea how this can be done aside from custom platform-specific converters?
Possibly a Xamarin.Forms.ImageSource function toByte()?
Lemme know if you need more information.
TargetImageSource is a Xamarin.Forms.ImageSource.
ImageSource TargetImageSource = null;
Solution (Sten was right)
The ImageSource has to originate from another type to exist, that previous type can be converted to a byte[]. In this case, I use the Xamarin.Forms.Labs to take a picture and it returns a MediaFile in which a FileStream is accessible through the Source property.
//--Upload image
//Initialization
HttpClient httpClient = new HttpClient ();
MultipartFormDataContent formContent = new MultipartFormDataContent ();
//Convert the Stream into byte[]
byte[] TargetImageByte = ReadFully(mediaFile.Source);
HttpContent httpContent = new ByteArrayContent (TargetImageByte);
formContent.Add (httpContent, "image", "image.jpg");
//Send it!
await httpClient.PostAsync ("https://api.magikweb.ca/xxx.php", formContent);
App.RootPage.NavigateTo (new ClaimHistoryPage());
The function:
public static byte[] ReadFully(Stream input)
{
using (MemoryStream ms = new MemoryStream()){
input.CopyTo(ms);
return ms.ToArray();
}
}
I think you're looking at it a bit backwards.
ImageSource is a way to provide a source image for Xamarin.Forms.Image to show some content. If you're already showing something on the screen your Image view was populated with data that came from elsewhere, such as a file or resource or stored in an array in memory... or however else you got that in the first place. Instead of trying to get that data back from ImageSource you can keep a reference to it and upload it as needed.
Maybe you can elaborate a bit on your particular need if you don't feel this solution applies to your case.
Pseudo code:
ShowImage(){
ImageSource imageSource = ImageSource.FromFile("image.png"); // read an image file
xf_Image.Source = imageSource; // show it in your UI
}
UploadImage(){
byte[] data = File.ReadAll("image.png");
// rather than
// byte[] data = SomeMagicalMethod(xf_Image.Source);
HttpClient.Post(url, data);
}
UPDATE:
Since you're taking a picture you can copy the MediaFile.Source stream into a memory stream, then you can reset the memory stream's position to point at the beginning of the stream so that you can read it once again and copy it to the http body.
Alternatively you can store the MediaFile.Source to a file and use ImageSource.FromFile to load it in the UI, and when necessary - you can copy the file's contents into an http post body.

Video Playing From Memory Stream

I am working in asp.net c#. I want to play video from memory stream. I am encrypting and decrypting video. I am storing the decrypted video in memory stream, and want to play it, without saving. I have googled it and found number of post, but mostly the post are uncompleted or provided the link with directshow. I have also tried with directshow, but it's totally new for me and contains number of demos, that made a confusion which one to use for Memory stream.
I just want to play decrypted video data from memory stream . Please let me know what I can do, it will be more good if there is a sample available from any forums.
My decrypted code
public bool DecryptData(String inName, String outName, byte[] rijnKey, byte[] rijnIV)
{
FileStream fin = null;
FileStream fout = null;
CryptoStream decStream = null;
try
{
fin = new FileStream(inName, FileMode.Open, FileAccess.Read);
//Create variables to help with read and write.
byte[] bin = new byte[bufLen]; //This is intermediate storage for the encryption.
long rdlen = 0; //This is the total number of bytes written.
long totlen = fin.Length; //This is the total length of the input file.
int len; //This is the number of bytes to be written at a time.
RijndaelManaged rijn = new RijndaelManaged();
//DES ds = new DESCryptoServiceProvider();
decStream = new CryptoStream(fin, rijn.CreateDecryptor(rijnKey, rijnIV), CryptoStreamMode.Read);
//odkoduj testowy fragment
byte[] test = new byte[testHeader.Length];
decStream.Read(test, 0, testHeader.Length);
string contents = new StreamReader(decStream).ReadToEnd();
byte[] unicodes = Encoding.Unicode.GetBytes(contents);
MemoryStream msOutput = new MemoryStream(unicodes);
//here I have to implement player that plays from memory stream.
}
catch
{}
}
I have answered one question regarding encrypting and decryption of a video file but i can understand you don't want to save a physical copy of that file on client machine.
https://stackoverflow.com/a/58129727/9869635
But it is not possible to play a video file from memorystream (not sure about some paid third party tools)
so one way you can do it like below approach:
1: Save that file in client's "temp" folder e.g. "temp/myvideos/sample.mkv"
2: Make it hidden from properties (How to hide file in C#?)
3: Play the video from there
4: once it is played, delete all files from that custom folder from "temp" folder (myvideos).
The best way to do it today, that works for any platform... is to use Http Live Streaming and then you can either use a player that supports HLS or you can simply use the HTML5 video tag. See my updated answer below...
Play a video without a file on disk [Java]

Cannot upload large (>50MB) files to SharePoint 2010 document library

I'm trying to upload a large file to a document library, but it fails after just a few seconds. The upload single document fails silently, upload multiple just shows a failed message. I've turned up the file size limit on the web application to 500MB, and the IIS request length to the same (from this blog), and increased the IIS timeout for good measure. Are there any other size caps that I've missed?
Update I've tried a few files of various sizes, anything 50MB or over fails, so I assume something somewhere is still set to the webapp default.
Update 2 Just tried uploading using the following powershell:
$web = Get-SPWeb http://{site address}
$folder = $web.GetFolder("Site Documents")
$file = Get-Item "C:\mydoc.txt" // ~ 150MB
$folder.Files.Add("SiteDocuments/mydoc.txt", $file.OpenRead(), $false)
and get this exception:
Exception calling "Add" with "3" argument(s): "<nativehr>0x80070003</nativehr><nativestack></nativestack>There is no file with URL 'http://{site address}/SiteDocuments/mydoc.txt' in this Web."
which strikes me as odd as of course the file wouldn't exist until it's been uploaded? N.B. while the document library has the name Site Documents, it has the URL SiteDocuments. Not sure why...
Are you sure you updated the right webapp? Is the filetype blocked by the server? Is there adequate space in your content database? I would check ULS logs after that and see if there is another error since it seems you hit the 3 spots you would need too update.
for uploading a large file, you can use the PUT method instead of using the other ways to upload a document.
by using a put method you will save the file into content database directly. see the example below
Note: the disadvantage of the code below is you cannot catch the object that is responsible for uploading directly, on other word, you cannot update the additional custom properties of the uploaded document directly.
public static bool UploadFileToDocumentLibrary(string sourceFilePath, string targetDocumentLibraryPath)
{
//Flag to indicate whether file was uploaded successfuly or not
bool isUploaded = true;
try
{
// Create a PUT Web request to upload the file.
WebRequest request = WebRequest.Create(targetDocumentLibraryPath);
//Set credentials of the current security context
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = “PUT”;
// Create buffer to transfer file
byte[] fileBuffer = new byte[1024];
// Write the contents of the local file to the request stream.
using (Stream stream = request.GetRequestStream())
{
//Load the content from local file to stream
using (FileStream fsWorkbook = File.Open(sourceFilePath, FileMode.Open, FileAccess.Read))
{
//Get the start point
int startBuffer = fsWorkbook.Read(fileBuffer, 0, fileBuffer.Length);
for (int i = startBuffer; i > 0; i = fsWorkbook.Read(fileBuffer, 0, fileBuffer.Length))
{
stream.Write(fileBuffer, 0, i);
}
}
}
// Perform the PUT request
WebResponse response = request.GetResponse();
//Close response
response.Close();
}
catch (Exception ex)
{
//Set the flag to indiacte failure in uploading
isUploaded = false;
}
//Return the final upload status
return isUploaded;
}
and here are an example of calling this method
UploadFileToDocumentLibrary(#”C:\test.txt”, #”http://home-vs/Shared Documents/textfile.pdf”);

Stream Video with ASP.NET

Is there a good way to stream video through asp.net to a normal webpage and mobile? I've tried the following but it doesn't work in my Sony Ericsson K810i. When I try it in my browser, I can see the clip (don't know if it's streaming though).
html:
<object type="video/3gpp"
data="handlers/FileHandler.ashx"
id="player"
width="176"
height="148"
autoplay="true"></object>
FileHandler.ashx (Best way to stream files in ASP.NET):
public void ProcessRequest (HttpContext context) {
string path = "~/files/do.3gp";
string localPath = context.Server.MapPath(path);
if (!File.Exists(localPath))
{
return;
}
// get info about contenttype etc
FileInfo fileInfo = new FileInfo(localPath);
int len = (int)fileInfo.Length;
context.Response.AppendHeader("content-length", len.ToString());
context.Response.ContentType = FileHelper.GetMimeType(fileInfo.Name); // returns video/3gpp
// stream file
byte[] buffer = new byte[1 << 16]; // 64kb
int bytesRead = 0;
using(var file = File.Open(localPath, FileMode.Open))
{
while((bytesRead = file.Read(buffer, 0, buffer.Length)) != 0)
{
context.Response.OutputStream.Write(buffer, 0, bytesRead);
}
}
// finish
context.Response.Flush();
context.Response.Close();
context.Response.End();
}
What you've got isn't "technically" streaming. It's a file download. Your client (browser/phone) sent an HTTP request and your FileHandler.ashx opened the file and wrote the bytes into the response stream. This is exactly the same interaction for a web page request except the data is html text rather than binary data representing a video.
If the phone isn't supporting the video it might be incompatible encoding. If you're sure the video is playable by the phone, see if the phone wants progressive download support (like the iPhone / iPad / iPod Touch require for the media player to "stream" videos.) If this is so, you'll need to look at any of a number of solutions that are available for handling requests for byte-range data and responding to the request with the bytes from the file in the range specified.
I wrote a library for ASP.NET MVC to handle this and my work was mostly done based on this guidance and source code.

Loading Html page and modifying a section

I need to load an external web (not local) page into my site (some link), but only a part of it.
What are the options for doing so?
That depends on whether or not the external page is local, or on a different domain. If it's local, you can use $.load() in the jQuery library. This has an optional parameter to specify which element in the remote-dom to load it:
$("#links").load("/Main_Page #jq-p-Getting-Started li");
If the page is on another domain, you'll need a proxy script. You can do this with PHP and the phpQuery (php port of jQuery) library. You'll just use file_get_contents() to get the actual remote-dom, and then pull out the elements you want based on jQuery-like selectors.
$f = fopen('http://www.quran.az/2/255', 'r');
and so on...
Once you get the whole page as Michael Todd outlined, you will likely need to either use substring methods for a static means to slice up the content or you can use regex's for a more dynamic way to grab the content. An intro article on Regex's in ASP.Net can be found here. Good luck!
To load a web page in .Net, use the HttpWebRequest class.
Example taken from MSDN, here:
private string StringGetWebPage(String uri)
{
const int bufSizeMax = 65536; // max read buffer size conserves memory
const int bufSizeMin = 8192; // min size prevents numerous small reads
StringBuilder sb;
// A WebException is thrown if HTTP request fails
try
{
// Create an HttpWebRequest using WebRequest.Create (see .NET docs)!
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
// Execute the request and obtain the response stream
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
// Content-Length header is not trustable, but makes a good hint.
// Responses longer than int size will throw an exception here!
int length = (int)response.ContentLength;
// Use Content-Length if between bufSizeMax and bufSizeMin
int bufSize = bufSizeMin;
if (length > bufSize)
bufSize = length > bufSizeMax ? bufSizeMax : length;
// Allocate buffer and StringBuilder for reading response
byte[] buf = new byte[bufSize];
sb = new StringBuilder(bufSize);
// Read response stream until end
while ((length = responseStream.Read(buf, 0, buf.Length)) != 0)
sb.Append(Encoding.UTF8.GetString(buf, 0, length));
}
catch (Exception ex)
{
sb = new StringBuilder(ex.Message);
}
return sb.ToString();
}
Note that this will return the entire page and not just a portion of it. You'll then need to sift through the page to find the information you're looking for.

Resources