Broadcasting video with Android - without writing to local files
One of the weaker points of the Android platform is the Media API. When compared to the J2ME API, one important feature is missing: the ability to record to a stream and to playback from a stream.
Why is this important? There are a number of use cases.
For recording:
- post-processing audio / video data before writing out to the file system
- broadcasting audio / video without writing out the data first into the file system, which also limits the broadcast to the available free space on the device.
For playback:
- pre-processing the audio / video data before playing
- streaming using protocols that are not supported by the built-in media player
In this blog entry we will show a method to broadcast video (and audio) from an Android phone to a network server, without writing to the file system.
There is one promising method in the MediaRecorder class setOutputFile(FileDescriptor).
We know that in Linux also network sockets have file descriptors. But how could we access the file descriptor of a regular java.net.Socket?
Luckily, ParcelFileDescriptor comes to the rescue, where we can use the fromSocket(Socket) static method to create a ParcelFileDescriptor instance from a Socket object. From this instance, we may now grab the badly needed FileDescriptor.
It all boils down to these few lines (in pseudocode):
String hostname = "your.host.name"; int port = 1234; Socket socket = new Socket(InetAddress.getByName(hostname), port); ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket); MediaRecorder recorder = new MediaRecorder(); // Additional MediaRecorder setup (output format ... etc.) omitted recorder.setOutputFile(pfd.getFileDescriptor()); recorder.prepare(); recorder.start();
Using this concept we created a small proof of concept application (together with an even simpler server), which is able to broadcast videos not limited in length by the available space on the SD Card.
There are a few gotchas, if you want to try this out yourself:
- The MediaRecorder records either in 3GPP or in MP4 format. This file format consists of atoms, where each atom starts with its size. There are different kinds of atoms in a file, mdat atoms store the actual raw frames of the encoded video and audio. In the Cupcake version Android starts writing out an mdat atom with the encoded frames, but it has to leave the size of the atom empty for obvious reasons. When writing to a seekable file descriptor, it can simply fill in the blanks after the recording, but of course socket file descriptors are not seekable. So the received stream will have to be fixed up after the recording is finished, or the raw video / audio frames have to be processed by the server.
- For some reason, the MediaRecorder also leaves the header of the file blank, which also has to be handled on the server.
- High latency connections will cause the video to be choppy. Obviously some buffering is necessary. One method is to use a local mini server on the phone which receives the stream, buffers it, and sends to the remote server as fast as the network allows it. However, if using native code is an option, we can simply create a pipe to receive the data from the MediaRecorder. We will show this method in a future blog entry.
Hozzászólások
very usefull
very usefull material,
thanks
Hi kisg, can you provide its
Hi kisg,
can you provide its full working source please?
really appreciate your help
Thanks for sharing great
Thanks for sharing great technique..
obviously very few people will know abt socket to fd.
thx
suds
Any tips for server side?
Hi
Can You please give some tips for the server side?
What are you using to capture/broadcast the stream?
thx
T
hi i have try to receive and
hi i have try to receive and play by MediaPlayer using this way
but i can't setup and play it.
could you give me some hint for that?
Socket socket = new Socket(serverAddr, PORT); //use tcp to receive
pfd = ParcelFileDescriptor.fromSocket(socket); //set pfd
MP = new MediaPlayer();
MP.setAudioStreamType(AudioManager.STREAM_MUSIC); //create MediaPlayer
MP.setDataSource(pfd.getFileDescriptor()); //set datasource by pfd
MP.prepare();
MP.start();
do i miss to set something?
thx
the same
Hi
i habe the save problem.
do u have got it out now?
thanks
Friend have you find any
Friend have you find any solution ?? plz let me know if you have.
Have u found its working.
Have u found its working, If yes then plz share it. I am get stuck at same point.
Thanks,
Parag Patel
Good post, but I have one more question...
Hi all,
really useful post... I would like to add one more element. I also need to stream raw data without any form of video encoding... is it possible to do???
Thanks and how about DatagramSocket?
Thanks for this wonderful post. I've been pulling my hair out on this for hours now. Is it possible to do a similar trick with a datagram socket?
Mark
Trying to get this to work
Hi kisg,
I've been trying to get this to work for a few weeks now... Do you have more information/documentation or code I could look at? It would be incredibly helpful if you could post them on the site or send them to me. Thanks.
Pat
Great
Great kisg,
please more details and snipped code, could be a success for all.
Thanks
Stefano
"For some reason, the
"For some reason, the MediaRecorder also leaves the header of the file blank, which also has to be handled on the server."
Any ideas how to handle this?
Is there a posibility to generate the header on the Server?
Awesome! Works flawlessly and
Awesome!
Works flawlessly and smooth!
I didn't even had to fix the stream, as the file generated on the server is working.
My previous attempt at this was to create 10s files and send them.
Repairing the Output
Just to help those having issues, the SDK seems to try to seek to insert the size values of the mdat atom, and also the moov header.
I set the encoder in this example to produce a THREE_GPP file.
In order to play the output THREE_GPP, you're going to need to first create the header in the first 28 bytes prior to the mdat atom (which should all be zeros).
00 00 00 18 66 74 79 70 33 67 70 34 00 00 03 00 33 67 70 34 33 67 70 36 00 02 F1 4D 6D
The 6D is the 'm' first byte in the mdat atom. The four bytes proceeding that need to be modified to include the integer value of the byte in your stream containing the output moov atom (Which should be output upon stopping the recording). As long as this header is correctly set, and the player can locate the moov atom- everything should play back correctly.
Also, the socket method here isn't very flexible- you can perform finer alterations of the packet data to a network (I'm attempting this at the moment for live streaming), by providing it with a local socket, and then connecting to that local socket and processing its output independently (In a thread for instance) for transmission over UDP, RTP, etc..
- Jason
Play incoming stream
Can we do same thing (user local socket) to receive incoming RTP stream which has H326 encodec data?
I have successfully send RTP stream, but when same way going to receive incoming RTP stream, MediaPlayer setDataSource function goes fail. giving me "offset error". I have looked Android MediaPlyer code, its giving error at below point.
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
return UNKNOWN_ERROR;
}
LOGV("st_dev = %llu", sb.st_dev);
LOGV("st_mode = %u", sb.st_mode);
LOGV("st_uid = %lu", sb.st_uid);
LOGV("st_gid = %lu", sb.st_gid);
LOGV("st_size = %llu", sb.st_size);
if (offset >= sb.st_size) {
LOGE("offset error");
::close(fd);
return UNKNOWN_ERROR;
}
Can any one help me to understand what I am doing wrong?
Thanks,
Parag Patel
It needs to understand the format.
Parag,
I'm trying to the same thing now- setting the data source to an fd with RTP data on it isn't going to work- since it has no ability to automatically detect the format type. There's no way to set this manually either :( MediaPlayer does support RTSP though, and it should be possible to send it the right SDP information to accomplish this.. I'm amazed nobody else has done this as far as I can tell...
- Jason Thomas.
Source
Hi Parag,
Can you please share the code for sending RTP stream?
Thanks,
Anu
sample code in sipdroid.org
you can get the sample code in VideoCamera.java in Sipdroid.org.
as for playback, it seems that android mediaplayer can not play rtp stream for lacking sdp information. if I am wrong, please correct me.
thanks.
Play the stream
Hi folks,
I think I made some code that works, with some help from this page and looking at the code of the sipdroid. Now I want to play this stream in my computer, but I don't know how. It tried with VLC but I couldn't make it work. I am using ubuntu 9.04. Someone have some tips for me? If you are interested in the code I can paste it here.
Regards,
Roger
Hi Roger, Sorry, don't have
Hi Roger,
Sorry, don't have any tips for you, but would love to see working code for this process.
Thanks!
Scott
nice work
you say J2ME can stream video to a server but I dont think it can?
The android code would be most useful but I will try this later, thanks for the great post.
Hi, You can specify
Hi,
You can specify setOutputStream for the RecordControl. Then you can take this stream and send it to a remote server through the network.
Best Regards,
Gergely
There's no
There's no "setOutputStream()" method for "MediaRecorder"
Hi, coudl you guys (blogger
Hi, coudl you guys (blogger or you others) that made it work all the way) so you can see whats being captured on the pc, share the code please?
Im having troubles figuring how to handle the stream at the other end (server)
I got the same troubles in
I got the same troubles in the other end too.
Android phones are the best.
Android phones are the best. When will iPhone renounce its software and use Android instead?
Cheap VPS
009 来祝贺
We are sell wow gold and wow power leveling and wow gold or knight noah
rolex
Carol Mueller said replica watches her husband remained replica consistently devoted tag heuer to this project fake rolex After coming up rolex with the idea
watches
spent every weekend replica watches working on it fake watches He would be out there watches all day Saturday replica rolex and all day Sunday cartier she said.While Keith breitling did most of the work
cheap NFL Jerseys Bastian
cheap NFL Jerseys
Bastian Schweinsteiger Jersey
Schweinsteiger Jersey
Lukas Podolski Jersey
Podolski Jersey
Miroslav Klose Jersey
Klose Jersey
Thomas Mueller Jersey
Mueller Jersey
Michael Ballack Jersey
Robin Van Persie Jersey
V.Persie Jersey
Arjen Robben Jersey
Robben Jersey
Wesley Sneijder Jersey
Sneijder Jersey
Andres Iniesta Jersey
A.Iniesta Jersey
David Villa Jersey
Xavi Hernandez Creus Jersey
Xavi Jersey
Fernando Torres Jersey
Torres Jersey
Cesc Fabregas Jersey
Fabregas Jersey
Sergio Ramos Jersey
Atlanta Braves jerseys
Baltimore Orioles jerseys
Boston Red Sox jerseys
Chicago Cubs jerseys
Chicago White Sox jerseys
Cincinnati Reds jerseys
Cleveland Indians jerseys
Detroit Tigers jerseys
Houston Astros jerseys
Houston Colts Jerseys
Kansas City Royals jerseys
Los Angeles Angels jerseys
Los Angeles Dodgers jerseys
Milwaukee Brewers jerseys
Minnesota Twins jerseys
Montreal Expos jerseys
New York Mets jerseys
New York Yankees jerseys
Oakland Athletics jerseys
Philadelphia Phillies jerseys
Pittsburgh Pirates jerseys
San Diego Padres jerseys
San Francisco Giants jerseys
Seattle Mariners jerseys
Seattle Pilots Jerseys
St.Louis Cardinals jerseys
Tampa Bay Rays jerseys
Texas Rangers jerseys
Toronto Blue Jays jerseys
Washington Nationals jerseys
" All shows are archived
" All shows are archived tissot on Hulu for viewing.
Click Here replica watches for the Blotter Homepage.
Gun breitling aeromarine Sales Expected to Shoot Up
Supreme tissot quadrato chronograph Court Ruling Seen as Windfall tudor women for Firearms Manufacturers, Dealers
By RICH knock off jewelry BLAKE
July 16, 2010
After a prs200 Supreme Court decision affirming the piaget replica right to bear arms was dior jewelery handed down in June, the gucci bracelets owners of Midwest Sporting Goods, rado watches for men just outside of Chicago, started baume & mercier riviera noticed something any retailer
Hozzászólás