Streaming Video (TAO.FFMPEG)
HI,
I tried to stream video data in C# (TAO.FFMPEG) from computer A to computer B, but I could not succeed.
I already have a working example in C and need to convert it to C#. Could someone help me to convert the piece of code?
source code in C:
int read_data(void *opaque, uint8_t *buf, int buf_size)
{
// first read from file, until ffmpeg works
// (later try to receive data from network)
FILE * fp = (FILE *) opaque;
if (!fp)
{
return -1;
}
int cnt = fread(buf, sizeof(uint8_t), buf_size, fp);
return cnt;
}
void * Reader(void * param)
{
Shared * ctl = (Shared *) param;
AVFormatContext *pFormatCtx;
int i, videoStream;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVPacket packet;
int frameFinished;
int buffer_current_pos;
FILE * fp = fopen(ctl->filename, "r");
// Register all formats and codecs
av_register_all();
uint8_t pDataBuffer[2048];
long lSize = 2048;
read_data(fp, pDataBuffer, lSize);
AVProbeData pd;
pd.buf = pDataBuffer;
pd.buf_size = lSize;
pd.filename = "";
AVInputFormat* pAVInputFormat = av_probe_input_format(&pd, 1);
if(!pAVInputFormat)
{
return false;
}
pAVInputFormat->flags |= AVFMT_NOFILE;
ByteIOContext ByteIOCtx;
if(init_put_byte(&ByteIOCtx, pDataBuffer, lSize, 0, fp, read_data, NULL, NULL) < 0)
{
return false;
}
if(av_open_input_stream(&pFormatCtx, &ByteIOCtx, "", pAVInputFormat, NULL) < 0)
{
return false;
}
if(av_find_stream_info(pFormatCtx) < 0)
{
return false;
}
// Dump information about file onto standard error
//dump_format(pFormatCtx, 0, ctl->filename, 0);
// Find the first video stream
videoStream = -1;
for(i = 0; i < pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
videoStream = i;
break;
}
}
if(videoStream == -1)
{
fprintf(stderr, "didn't find a video stream\n");
Abort(ctl);
return 0; // Didn't find a video stream
}
... (skip the rest)
}
Could someone write a similar program that uses av_open_input_stream, av_init_put_byte and ByteIOContext with the help of TAO.FFMPEG?

The source code in C# with
The source code in C# with TAO.FFMPEG could look like this:
public class Test
{
static BinaryReader file_ = new BinaryReader(new FileStream(@"C:\tmp\dc.mov", FileMode.Open, FileAccess.Read));
public static bool test()
{
FFmpeg.av_register_all();
FFmpeg.avcodec_register_all();
byte[] data = TestRead();
IntPtr pDataBuffer = Marshal.AllocHGlobal(2048 * sizeof(byte));
Marshal.Copy(data, 0, pDataBuffer, 2048);
int lSize = 2048;
IntPtr pPd = Allocate<FFmpeg.AVProbeData>();
FFmpeg.AVProbeData pd = PtrToStructure<FFmpeg.AVProbeData>(pPd);
pd.buf = pDataBuffer;
pd.buf_size = lSize;
pd.filename = "";
Marshal.StructureToPtr(pd, pPd, false);
IntPtr pAVInputFormat = FFmpeg.av_probe_input_format(pPd, 1);
if(pAVInputFormat == IntPtr.Zero)
{
return false;
}
FFmpeg.AVInputFormat inpFormat = PtrToStructure<FFmpeg.AVInputFormat>(pAVInputFormat);
inpFormat.flags |= (int) FFmpeg.AVFMT_NOFILE;
Marshal.StructureToPtr(inpFormat, pAVInputFormat, false);
IntPtr pByteIOCtx = Allocate<FFmpeg.ByteIOContext>();
if (FFmpeg.init_put_byte(pByteIOCtx, pDataBuffer, lSize, 0, IntPtr.Zero, MyRead, null, null) < 0)
{
return false;
}
IntPtr pAVFormatContext = FFmpeg.av_alloc_format_context();
if (FFmpeg.av_open_input_stream(out pAVFormatContext, pByteIOCtx, "", pAVInputFormat, IntPtr.Zero) < 0)
{
return false;
}
if(FFmpeg.av_find_stream_info(pAVFormatContext) < 0)
{
return false;
}
return true;
}
private static int MyRead(IntPtr opaque, IntPtr buf, int buf_size)
{
byte[] ret = TestRead();
Marshal.Copy(ret, 0, buf, ret.Length);
return ret.Length;
}
public static byte[] TestRead()
{
byte[] ret = new byte[2048];
file_.Read(ret, 0, 2048);
return ret;
}
static T PtrToStructure<T>(IntPtr pointer)
{
return (T)Marshal.PtrToStructure(pointer, typeof(T));
}
static IntPtr Allocate<T>()
{
return Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)));
}
}
}
The problem is, that there raises an AccessViolationException when calling FFmpeg.av_open_input_stream().
As far as I can see,
As far as I can see, init_put_byte expects a file pointer, which you don't have in C#, so it can't read beyond the initial 2048 byte buffer. Out of curiosity, why don't you just use the managed stream reader available in one of the examples?
Ok, I'll give it a try. You
Ok, I'll give it a try. You mean MediaFile.cs of the TaoMediaplayer project?
There's a next question:
The class MediaFile uses a Seek-Method (delegate) to seek the position within the stream. I want to use a System.Net.Sockets.NetworkStream (or is there a better choice?) to stream the data over the network. The problem is, that the NetworkStream's CanSeek property is set to false and thus s.Seek(...) ends in an exception. How do I change the MediaFile class to handle streams without the ability to seek? Or do I have to write my own network stream that can seek?
Is there an example of such a network stream or an example of how to stream videos over the network?
Thanks!
FFmpeg's own network stream
FFmpeg's own network stream just sets the seek function to Null, so you should try to see what happens if you just don't set the seek delegate...
When I set the seek function
When I set the seek function to null, the function FFmpeg.av_read_frame always returns -1. I don't know why...
I used MediaFile.cs of the TaoMediaplayer project and tried the following code to test it:
media = new MediaFile(@"C:\tmp\dc.mov");IntPtr buffer = Marshal.AllocHGlobal(media.Width*media.Height*3);
// Load next frame, or stop playing if eof
double time = (double)timer.ElapsedMilliseconds / 1000.0;
playing = media.NextVideoFrame(buffer, Tao.FFmpeg.FFmpeg.PixelFormat.PIX_FMT_RGB24, ref time);
If I change the line (constructor of MediaFile)
protocol.seekfunc = Seek;to
protocol.seekfunc = null;FFmpeg.av_read_frame() in ReadPacket() always returns -1.
Do you know why? Or could someone test and correct it?
Thanks