I am trying to implement a Java servlet that runs on Tomcat, capable of streaming multiple FLV files to client browsers having JWPlayer. The catch is I have to stream multiple files one at a time and sometimes start streaming from the middle of the first clip and I need JWPlayer to think that the file duration is the duration of all the clips combined.
My servlet would work well if I merged all of the clips to one single FLV file, injected the metadata (using yamdi) and then streamed it. But this can be pretty time consuming. I've tried sending the player the meta information for the file that I stream from the middle first and then go ahead and stream it from the middle but this doesn't seem to work. I've tried fiddling with the duration parameter in the metadata to no avail.
I think that this is because I'm skipping tags when i start to stream from the middle of the clip. Would it be humanly possible to construct tags while processing the byte stream before the servlet sends it out?
You don't need the meta data, other than the initial FLV header and individual frame descriptions. As long as your FLV frames are correctly and atomically started and stopped, what you are doing seems very possible to me. (I had considered doing something similar, having already written an FLV parser.) Be sure not to send a Length header. ;) Two things might make all of this much easier to accomplish:
ensure you've encoded your video with smallish key frame interval. You won't be able to jump between clips at any finer of a resolution than this. Anything less that 1s is probably going to be problematic, much higher video rates.
pre-parse all your video files into segments. When the servlet is called,
send the FLV header
read and write whole segment files to the client
1- to switch videos, move to another group of segment files
Example that assumes you want to send each original file from the start:
send(FLV_HEADER)
i = 0
while(send file 1 condition == true)
send(file-1-segment i++)
i = 0
while(send file 2 condition == true)
send(file-2-segment i++)
(Alternatively you could map some indexes and use them to read frames from the middle of a file. Been there, done that.)
Related
I'm trying to record from the microphone to a wav file as per this example. At the same time, I need to be able to test for input level/volume and send an alert if it's too low. I've tried what's described in this link and seems to work ok.
The issue comes when trying to record and read bytes at the same time using one TargetDataLine (bytes read for monitoring are being skipped for recording and vice-versa.
Another thing is that these are long processes (hours probably) so memory usage should be considered.
How should I proceed here? Any way to clone TargetDataLine? Can I buffer a number of bytes while writing them with AudioSystem.write()? Is there any other way to write to a .wav file without filling the system memory?
Thanks!
If you are using a TargetDataLine for capturing audio similar to the example given in the Java Tutorials, then you have access to a byte array called "data". You can loop through this array to test the volume level before outputting it.
To do the volume testing, you will have to convert the bytes to some sort of sensible PCM data. For example, if the format is 16-bit stereo little-endian, you might take two bytes and assemble to either a signed short or a signed, normalized float, and then test.
I apologize for not looking more closely at your examples before posting my "solution".
I'm going to suggest that you extend InputStream, making a customized version that also performs the volume test. Override the 'read' method so that it obtains the byte that it returns from the code you have that tests the volume. You'll have to modify the volume-testing code to work on a per-byte basis and to pass through the required byte.
You should then be able to use this extended InputStream as an argument when you create the AudioInputStream for the output-to-wav stage.
I've used this approach to save audio successfully via two data sources: once from an array that is populated beforehand, once from a streaming audio mix passing through a "mixer" I wrote to combine audio data sources. The latter would be more like what you need to do. I haven't done it from a microphone source, though. But the same approach should work, as far as I can tell.
Lets say I have this video url : http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4
and I need to download just a small playable snippet from this video (e.g. 00:24 - 00:30).
How should I do this in java? And I don't want to download the entire video and then cut it.
I already looked at the network tab of chrome and read the request and response headers but couldn't get much sense of it, except:
"Range:bytes=0-" in the request header
"Content-Length:5510872" in the response header
But I can't just choose any range because it would make the video not playable right?
So how does the browser know which range it should get if I click on 00:24?
assuming you're working with .mp4 containers,
the mp4 file format contains a hierarchical structure of 'boxes' (aka "atoms'). The magic for fast seeking lies in the moov atom which is why when encoding a video for web it's always best to optimize the structure of the file and relocate that to the front so that the browser has access to the metadata as the very first thing it downloads.
moov
Movie box which is the container for all metadata
Each moov has have a mvhd (Movie header box)
It can contains N trak box(es). Each trak box contains media specific meta data information Usually, it will have 2 tracks (video and audio)
More importantly, it contains sample information such as stsd, stts, stsz stsc, stco, etc...
stts - Time-To-Sample (stts) box.
This box contains the time of every frame (in a compact fashion). From here you can find the 'chunk' that contains the frame using the Sample-to-Chunk (stsc) atom. And finally the Chunk offset atom (stco) gives you the byte offset into the file.
Projects like MP4Parser or Xuggler can get you started on processing the MP4 container yourself (have samples on reading the underlying MP4 structure), but it's not a trivial undertaking - sadly there doesn't seem to be a comprehensive MP4 API toolkit for Java
An online link gives me back a video in my browser, that is then streamed. In my browser, I don't need to download the whole video to visualize it - I can skip to a certain part, visualize that part, and even stop watching before the end.
How can I, from the very same link, start to stream from a specific time onwards until another specific time, and each time save every frame I received to a video file?
I do know that I need to decode the data I get.
I also know that I need to somehow access the metadata of the video file.
However, I don't know how to deal with it in practice.
I tried out JCodec, but could not find how to deal with internet streams instead of opening files.
How can I properly stream parts of an online video, frame-by-frame, while also having access to metadata such as total video length, resolution, and FPS?
To answer the first parts of your question:
Trim videos with start offset and either end offset or duration (in seconds, percentages, etc.), e.g. http://res.cloudinary.com/demo/video/upload/so_6.5,eo_10/dog.mp4
Grab frames at desired timestamps along the original video, e.g. http://res.cloudinary.com/demo/video/upload/so_8.5/dog.jpg to save a JPEG-format frame at 8.5 seconds from the start of the video.
I've a stream with contains a audio/video stream. The video encoding is H.264 AVC and the audio encoding is G.711 ยต-law (PCMU). (I have no control over the output format.)
When I try to display the video into a VideoView frame, the device says that it cannot play the video. I guess that's because Android doesn't support the aforementioned audio encoding.
Is there a way to somehow display the selected stream in the VideoView?
Can I just use a Java code snippet to 'compute' the codec? I've seen the class android.net.rtp.AudioCodec, which contains a field PCMU, and I can imagine that class would be useful.
Or do I have to insert a library or some native code (FFmpeg) into my application and use that? If yes, how?
How to fix it?
If you want to manipulate a stream before you display it, you are unfortunately getting into tricky territory on an Android device - if you do have any possibility of doing the conversion on the serve side it will likely by much easier (and you should also usually have more 'horsepower' on the server side).
Assuming that you do need to convert on the server side, then a technique you can use is to stream the video from the server to your app, convert it as needed and then 'stream' from a localhost server in your app to a VideoView in your app. Roughly the steps are:
Stream the encrypted file from the server as usual, 'chunk by chunk'
On your Android device, read from the stream and convert each chunk as it is received
Using a localhost http server on your Android device, now 'serve' the converted chunks to the MediaPlayer (the media player should be set up to use a URL pointing at your localhost http server)
An example of this approach, I believe, is LibMedia: sure: http://libeasy.alwaysdata.net (note, this is not a free library, AFAIK).
For the actual conversion you can use ffmpeg as you suggest - there are a number of ffmpeg wrapper for Android projects that you can either use or look at to design your own. Some examples:
http://hiteshsondhi88.github.io/ffmpeg-android-java/
https://github.com/jhotovy/android-ffmpeg
Take a look at the note about libffmpeginvoke in the second link in particular if you are planning to write your won wrapper.
One thing to be aware of is that compressions techniques, in particular video compression, often use an approach where one packet or frame is compressed relative to the frames before it (and sometimes even the frames after it). For example the first frame might be a 'key frame', the next five frames might just contain data to explain how they differ from the key frame, and the the seventh frame might be another key frame and so on. This means you generally want a 'chunk' which has all the required key frames if you are converting the chunk from one format to another.
I don't think you will have this problem converting from PCM to AAC audio, but it useful to be aware of the concept anyway.
I want to split a video file into multiple parts and then rejoin some of them to make a new video file.
I am doing it by looping over the packets using xuggle and then writing some of them (after adjusting its timestamps) to the new file, but when I play the file, there is some disturbance in the transition frames. (It might be because the decoding of frame depends upon its preceding frame which has been discarded as part of the program)
How can I get rid of the disturbance?
Ideally you split on keyframes, since they usually don't depend on preceding frames.
The IPacket class has a isKey function to test for this condition.
I'm not sure what sort of compression format you are working with though. I have tried splitting a mp4 stream with xuggler, and found the results to be quite buggy.