Click here to Skip to main content
15,891,906 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more: , +
Hello,

First of all - sorry for my English :)

I'm trying to write C# program which will be download some media file via HTTP and play it at the same time.
It will be something like YouTube flashplayer.
But I'm using DirectShowNet lib to render video/audio.

Here you may ask yourself why this guy doesn't use "File source (URL)" filter instead of "File Source (Async)" filter? I know it will be easier but I'd like to manage process of file downloading.

I have no problems with file downloading separately and with file rendering separately.

DirectShow can render file even if it wasn't completely downloaded. Actually you should worry only about "Start" of media file (I guess there are media info).

And the question at last:
I write a file using something like the following code (in separate thread):
Stream strLocal = new FileStream(sTempLocalFilePath,
                                 FileMode.Append,
                                 FileAccess.Write,
                                 FileShare.Read,
                                 downBuffer.Length,
                                 FileOptions.Asynchronous)
while ((bytesSize = strResponse.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
  strLocal.Write(downBuffer, 0, bytesSize);
}

When I try to render the file I have an error - file is used by another process.
I close Stream strLocal,render file (it's playing) and then I'm trying to open Stream strLocal again but you know - file is used by another process.

How can I write to the file which is using by DirectShow?

PS: I've read the following articles but they didn't help me :-O :
- http://www.java2s.com/Tutorial/CSharp/0300__File-Directory-Stream/AsyncFileStream.htm
- http://www.codeproject.com/KB/threads/asyncFileIO.aspx

Thanks for any help.

--
Timur
Posted

If DirectShow has already started rendering the file, then it's unlikely that you can write to it. Do it in reverse. Create the filestream with FileShare.Read and FileAccess.Write, write the first few hundred bytes, then pass control to DirectShow which will then open the file and start rendering it, and then continue writing to your file.

Right now the reason I think it's failing is that DirectShow will not open it with any share modes enabled, so your attempt to open the file for writing will fail.
 
Share this answer
 
v2
Nishant, thanks for the answer. Do you think that DirectShow blocks file for writing when it's playing? I believe "File Source (Async.)" filter supports asynchronous I/O. Anyway, here is example how I try to play and download file at the same time:

private void OpenAndPlay(string FileName, bool isURL)
{
.....
	IFileSourceFilter fs = ds_FileSourceFilter as IFileSourceFilter;
	if (isURL)
	{
		Thread thread = new Thread(new ThreadStart(DownloadToPlay));
		sTempLocalFilePath = Path.GetTempFileName();
		thread.Start();
		WaitFile = true;
		_waitFile.WaitOne();
		fs.Load(sTempLocalFilePath, null);
	}
	else
	{
		fs.Load(sFileName, null);
	}
.....
	hr = ds_GraphBuilder.Render(ds_FileSourceFilterOutput);
	DsError.ThrowExceptionForHR(hr);
.....
	_waitFile.Set();//after this "DownloadToPlay" thread back to work but file is blocked for writing
	WaitFile = false;
.....
}

private void DownloadToPlay()
{
	// Create a request to the file we are downloading
	HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(sFileName);
	// Set default authentication for retrieving the file
	webRequest.Credentials = CredentialCache.DefaultCredentials;
	// Retrieve the response from the server
	HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
	Stream strResponse;
	// Open the URL for download 
	strResponse = webResponse.GetResponseStream();
	// It will store the current number of bytes we retrieved from the server
	int bytesSize = 0;
	// A buffer for storing and writing the data retrieved from the server
	byte[] downBuffer = new byte[64*1024];
	// Loop through the buffer until the buffer is empty
	Stream strLocal = new FileStream(sTempLocalFilePath, FileMode.Append, FileAccess.Write, FileShare.Read);
	while ((bytesSize = strResponse.Read(downBuffer, 0, downBuffer.Length)) > 0)
	{
		strLocal.Write(downBuffer, 0, bytesSize);
		if (WaitFile == true)
		{
			strLocal.Close();
			_waitFile.Set();
			_waitFile.WaitOne();
			strLocal = new FileStream(sTempLocalFilePath, FileMode.Append, FileAccess.Write, FileShare.Read);
		}
	}
	strLocal.Close();
	strResponse.Close();
	webResponse.Close();
	webRequest.Abort();
}


If you have any ideas how I can continue download a file please share with me.

Thanks.
--
Timur
 
Share this answer
 
Comments
Christian Graus 23-Jan-11 8:27am    
Please don't use the answer button to ask more questions, note the comment button that I used to reply. In response - what Nish said is true. DirectShow has NOTHING to do with it. In Windows you cannot have one block of code write a file, and another block of code reading it at the same time.
TimGameDev 23-Jan-11 9:54am    
Oh, sorry about the "answer"...I'm newbie here.

That's the bad news :( I believe there should be solution...
Probably I should use some temp file for downloading and temp file for playing and somehow merge them...
Or create some buffer and render file from it...is this possible in DirectShowNet?
TimGameDev 31-Jan-11 8:54am    
I just want to say that I've decided to use the following solution:
Download small parts of media file, merge them into two files. When first is playing then write to second file and vice versa.
Probably this is not best solution. May be I can use "Stream Buffer Engine Filters":
http://msdn.microsoft.com/en-us/library/ms787714%28v=vs.85%29.aspx
but it doesn't support many formats of media files.
At the moment I'm working with algorithm of render media from both files depend on current position of IMediaSeeking.

Anyway thanks for help guys :)
--
Timur

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900