Most websocket examples I have seen use either mp4 or wbem container data. Here is some sample javascript client code:
var ms = new MediaSource();
...
var buf = ms.addSourceBuffer('video/mp4; codecs="avc1.64001E"');
In my case, my server sends raw h264 data (video only, no audio). As there is no mp4/avc container for my data, I am wondering what is the proper way to define the parameter for addSourceBuffer(). Do I simply omit video/mp4 tag as follows? Regards.
var buf = ms.addSourceBuffer('codecs="avc1.64001E"');
I worked on a h264 play based on MediaSource several months ago. I didn't expect getting ups after such a long after the original answer, and I think I should edit this post to be more helpful. BTW I'm not a pro, this post is just based on my experience of using MediaSource API. Comments are welcome to correct me. Thanks!
var buf = ms.addSourceBuffer('video/mp4; codecs="avc1.64001E"');
After buf is created, I think buf expects fragmented MP4 data chunk each time when SourceBuffer.appendBuffer is called.
However you passed RAW H264 data to it which I think browser should give you an exception.
In my case, I used ffmpeg to read from a RTSP stream, convert the data to fMP4 format (without encoding) and send the output to stdout and then let other application to send the data to the browser. (I used WebSocket in fact.)
Here's the parameters:
ffmpeg -i rtsp://example.com/ -an -c:v copy -f mp4 \
-movflags +frag_keyframe+empty_moov+default_base_moof pipe:1
There's one more thing I want to share. I'm not sure how ffmpeg works, but it doesn't output a completed fragment each time I read from stdout. So in my backend program, I cached the data first. Here's pseudocode in Java:
byte[] oldbuf;
byte[] buffer = ReadDataFromFfmpegStdout();
if (buffer[4] == 'm' && buffer[5] == 'o' && buffer[6] == 'o' && buffer[7] == 'f') {
send(oldbuf); // the old buffer is a completed fragment now
oldbuf = buffer;
} else {
append(oldbuf, buffer); // append data to the old buffer
}
[ORIGINAL ANSWER]
You may checkout this project 131/h264-live-player on GitHub, which is based on mbebenita/Broadway, a JavaScript H.264 decoder.
The example of node server-static.js streams a raw h264 video over WebSocket, and the client code render it in a canvas. Git clone that repo, follow the installation instruction, put you h264 file in the samples folder, modify video_path to your video file in server-static.js#L28, execute the node server-static.js and you will see the video played in your browser.
Please be aware that, Broadway can only work with baseline profile.
Related
I am generating an rtsp stream using gstreamer in an iOS app and trying to use ffmpeg in a Mac OS X audio driver that I wrote using XCode to strip the audio out of the stream and then pump the audio to Skype or Zoom or whatever. All the code is written in the 'C' old-fashioned programming language. I do get a FILE* that is not NULL back from a popen function call to execute ffmpeg on the input rtsp stream. But once I get that FILE* object and try to read binary data from it, it returns that zero bytes have been read. Here is the code:
FILE *readPipeFromFFMPEG = popen("Contents/MacOS/ffmpeg -i rtsp://192.168.0.30:8554/test -vn -acodec copy -flush_packets pipe:1", "r+");
int pipeFD = fileno(readPipeFromFFMPEG);
char *buffer = (char*)calloc(inIOBufferFrameSize * 8, 1);
numBytesRead = read(pipeFD, buffer, inIOBufferFrameSize * 8);
free(buffer);
pclose(readPipeFromFFMPEG);
but numBytesRead is always coming back as zero. Does anybody have any clue what I need to do to get this working properly? It seems like maybe a permissions issue where I do not have permission to read from the stream? Or maybe my ffmpeg parameters are incorrect? I am able to open up the stream in VLC and OBS Studio no problem and it displays the video frames and plays the audio. I am really stuck I need help! I must be missing something totally obvious because when I run OBS Studio or VLC it shows in the iPhone app the requests from the client because it prints out information that the audio and video packets are being requested but when the audio driver is running nothing is printed out in the iPhone app.
I've written a sample in nodejs which streams some input to the client via websocket connection in mp4 format. On the client side, the mp4 packages are added to a MediaSourceBuffer.
This runs fine, but only if the client gets the stream from the beginning with the first package. So another client can't play the current Stream, because he won't get the Stream from the beginning.
I tried (try&error) to save the first package ffmpeg sends and send this at the beginning of a new connection, then the current stream. Then the MediaSourceBuffer breaks because of encoding error..
Here is the ffmpeg command :
-i someInput -g 59
-vcodec libx264 -profile:v baseline
-f mp4 -movflags empty_moov+omit_tfhd_offset+frag_keyframe+default_base_moof
-reset_timestamps 1
-
The part "empty_moov+omit_tfhd_offset+frag_keyframe+default_base_moof" should make the Streampackages independent in putting the moovatom at the beginning of each part and sizing the parts in 59 frames each by keyframe, so I don't get it why I can't view the Stream beginning after the start.
The output of that command is not a 'stream' per se. It is series of concatenated fragments. Each fragments must be received in its entirety. If a partial fragment is received it will confuse the parser to the point where it can not identify the start of the next fragment. In addition, the first fragment output is called an initialization fragment. This initialization fragment must be sent to the client first. After that any fragment can be played. Hence it must be cached by the server.
I am trying to use ffmpeg, and have been doing a lot of experiment last 1 month.
I have not been able to get through. Is it really difficult to use FFmpeg?
My requirement is simple as below.
Can you please guide me if ffmpeg is suitable one or I have implement on my own (using codec libs available).
I have a webm file (having VP8 and OPUS frames)
I will read the encoded data and send it to remote guy
The remote guy will read the encoded data from socket
The remote guy will write it to a file (can we avoid decoding).
Then remote guy should be able to pay the file using ffplay or any player.
Now I will take a specific example.
Say I have a file small.webm, containing VP8 and OPUS frames.
I am reading only audio frames (OPUS) using av_read_frame api (Then checks stream index and filters audio frames only)
So now I have data buffer (encoded) as packet.data and encoded data buffer size as packet.size (Please correct me if wrong)
Here is my first doubt, everytime audio packet size is not same, why the difference. Sometimes packet size is as low as 54 bytes and sometimes it is 420 bytes. For OPUS will frame size vary from time to time?
Next say somehow extract a single frame (really do not know how to extract a single frame) from packet and send it to remote guy.
Now remote guy need to write the buffer to a file. To write the file we can use av_interleaved_write_frame or av_write_frame api. Both of them takes AVPacket as argument. Now I can have a AVPacket, set its data and size member. Then I can call av_write_frame api. But that does not work. Reason may be one should set other members in packet like ts, dts, pts etc. But I do not have such informations to set.
Can somebody help me to learn if FFmpeg is the right choice, or should I write a custom logic like parse a opus file and get frame by frame.
Now remote guy need to write the buffer to a file. To write the file
we can use av_interleaved_write_frame or av_write_frame api. Both of
them takes AVPacket as argument. Now I can have a AVPacket, set its
data and size member. Then I can call av_write_frame api. But that
does not work. Reason may be one should set other members in packet
like ts, dts, pts etc. But I do not have such informations to set.
Yes, you do. They were in the original packet you received from the demuxer in the sender. You need to serialize all information in this packet and set each value accordingly in the receiver.
Problem:
I have to save live video streams data which come as an RTP packets from RTSP Server.
The data come in two formats : MPEG4 and h264.
I do not want to encode/decode input stream.
Just write to a file which is playable with proper codecs.
Any advice?
Best Wishes
History:
My Solutions and their problems:
Firt attempt: FFmpeg
I use FFmpeg libary to get audio and video rtp packets.
But in order to write packets i have to use av_write_frame :
which seems that decode /encode takes place.
Also, when i give output format as mp4 ( av_guess_format("mp4", NULL, NULL)
the output file is unplayable.
[ any way ffmpeg has bad doc. hard to find what is wrong]
Second attempth: DirectShow
Then i decide to use DirectShow. I found a RTSP Source Filter.
Then a Mux and File Writer.
Cretae Single graph:
RTSP Source --> MPEG MUX ---> File Writer
It worked but the problem is that the output file is not playable
if graph is not stoped. If something happens, graph crashed for example
the output file is not playable
Also i can able to write H264 data, but the video is completely unplayable.
The MP4 file format has an index that is required for correct playback, and the index can only be created once you've finished recording. So any solution using MP4 container files (and other indexed files) is going to suffer from the same problem. You need to stop the recording to finalise the file, or it will not be playable.
One solution that might help is to break the graph up into two parts, so that you can keep recording to a new file while stopping the current one. There's an example of this at www.gdcl.co.uk/gmfbridge.
If you try the GDCL MP4 multiplexor, and you are having problems with H264 streams, see the related question GDCL Mpeg-4 Multiplexor Problem
I am a newbie Mac programmer just for 3 months. I got a Audio Queue Services problem, hope anyone can help me.
I using Audio Queue Services API created a recording program, and output AAC format data. It's seems good, everything work fine.
Until I get to use the MP4V2 Library(an open source library) to output a .mp4 file, the problem is occur.
Problem 1:
I use magic cookie as a AAC header
to input to MP4V2 library function
MP4WriteSample(). Inside the .mp4 file has data, but the
player(ex:Quicktime) can't recognized
the .mp4 file, it can't play the audio data.
Problem 2:
I set my audio queue basic descriptions format in following :
aqData.mDataFormat.mSampleRate = 44100.0;
aqData.mDataFormat.mFormatID = kAudioFormatMPEG4AAC; // AAC codec.
aqData.mDataFormat.mChannelsPerFrame = 2;
aqData.mDataFormat.mFramesPerPacket = 1024;
and use AudioQueueGetProperty() to get magic cookie.
Than I print out my magic cookie contants, like that:
<03808080 22000000 04808080 14401500 18000001 f4000001 f4000580 80800212 10068080 800102>
total 39 Bytes.
What exactly it mean?
What the 39 Bytes each represented mean?
Can it convert to AAC header?
Reference :
Set a Magic Cookie for an Audio File
Set a Magic Cookie for a Playback Audio Queue
CoreAudio - how to determine the end of the playing aac file
Thanks a lot.
Ryan
set file type to kAudioFileM4AType
AudioFileCreateWithURL (
audioFileURL,
kAudioFileM4AType,
&audioFormat,
kAudioFileFlags_EraseFile,
&audioFileID
);