I have a video file that is encoded. For example the first bit of each byte is reversed. I want to read this video file, change the first bits and send the decoded result to Mediaplayer.
How can I do that? How can I create and pass this stream to media player without saving the decoded data on storage?
It is important that I do not want to save a decoded copy of my video and play it on media player. I want to play encoded video directly on mediaplayer using streams or other possible ways.
Short answer: NO, there is no way to do that (obviously by my point of view)
You cannot reproduce from a "custom" stream by manipulating the data just before passing it the MediaPlayer.
Why?
The official MediaPlayer API which is closest to the one needed to achieve your goal is the following:
MediaPlayer mp = new MediaPlayer();
FileInputStream fis = new FileInputStream(yourFile);
mp.setDataSource(fis.getFD());
//...
This snippet allows to play a file starting from a FileInputStream, but more precisely from the underlying FileDescriptor. The FileDescriptor is a class which is marked as final (and it is reasonable because it has to deal with the underlying OS), so you cannot override anything.
Possible workarounds?
As you already pointed out, you can try to modify the real file "in-place" while reproducing the video with the standard MediaPlayer (without creating a deep/separate copy of it): it's very tricky but plausible.
Try to use another player object: ExoPlayer (which is a new standard Android API) or Vitamio
Try a pure native solution (NDK + Android source), which I will not recommend ;)
UPDATE: detail about the 1st workaround
Assuming that "the first bit of each byte is reversed" you can use a FileChannel to manipulate the whole file "in-place" while reading it. You should use a FileChannels created from a RandomAccessFile created in mode "rw" in order to be able to read/write simultaneously.
This pre-elabaration task can run on a separated thread (or inside an IntentService, which is more fashion and reliable); you can wait for few seconds after the elaboration begins and then starting the playback by passing the File reference to the standard MediaPlayer (you need to tune this waiting period considering how fast is the elaboration, like a streaming buffering but easier because performance are almost stable).
In this way you don't need to wait the end of the pre-elaboration before starting the playback.
When the playback stops or you close the app, you need to undo your work by calling the same pre-elaboration task on the played file in order to restore it to its original state.
I hope that this hint can be useful.
Comments and precisations about my answer are welcome, I will update my post if I'll find more information.
Related
I have XOR'ed media files.
I want to play them with MediaPlayer class. Is it possible to decrypt media flow on the fly (and be able to rewind them)?
Shortly, I want to have all functionality of MediaPlayer class for XOR'ed media files.
Thanks in advance!
MediaPlayer may be too high level to accomplish this. I would suggest taking a look at AudioTrack. If you read your file in using an InputStream then you could XOR the data before feeding it to an AudioTrack instance. The only downfall to this approach is you will need to implement your own seek mechanism.
I am trying to stream incoming AMR_NB. I can't use MediaPlayer directly because it requires a seekable file. I would like to use MediaCodec, but to use MediaCodec I need (I think... please correct me!) MediaExtractor to give me things like the presentationTime. Is that true? Can I use MediaCodec without MediaExtractor?
MediaExtractor seems to require seekable files. The documentation only specifically says so for one of the setDataSource operations but when I tried to use any of the others it failed due to failed seek attempts.
So, what can I do to get my incoming AMR stream to play? I am aware of a scheme where by you save incoming data to a file and periodically make a copy of that file to feed to MediaPlayer but I'd really prefer to find a real honest streaming solution.
Is it possible to use MediaCodec without using MediaExtractor? If so how do I find presentation time and the string to pass to MediaCodec.createDecoderByType? The documentation SAYS that "audio/3gpp" is what I want but when I attempt to use that I get the following error:
codec = MediaCodec.createDecoderByType("audio/3gpp");
01-02 03:59:36.980: E/OMXMaster(21605): A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.
So I'm not sure how to get at MediaCodec either.
"I can't use MediaPlayer directly because it requires a seekable file" This is not generally true. I would like you to try it on your stream and report exactly what happens.
"Can I use MediaCodec without MediaExtractor?" I doubt it: I believe they are designed to be used together.
I have used these components to play streams. However, the MediaExtractor has limitations that are not documented ( as far as I know ). So use a little proxy server to feed it things it can digest. And I have 1 thread to run the MediaExtractor and another to take output from the the MediaCodec. Then i have to avoid deadlocks and cope with snchronization. But it is not that bad provided you just want to play forwards only. Then you have only the problem of how to stop!
I advise that you try MediaPlayer first. Otherwise, if you are keen enough to try the MediaExtractor, we could share our discoveries about what it will and wont digest. Don't take anything for granted. For example it seems it will play my MP3 files, but cannot discover their duration, or seek on them!
I need to implement a playback of separate audio files in N channels, files may play sequentially or in parallel. I need to implement it on Android.
Timeline:
|file a...|file d....|file b...|......|file k|....
|.....|file g|file c..|file p.|....
I'm thinking two options, one being FMOD to decompress files and play them simultaneously. I have researched and FMOD seems to fit well and much easier than manually playing this using an AudioTrack. However, I can't understand if FMOD would allow us to save the entire merged output without playing it through.
I know that using solution here we can redirect output to a wav file, but is it possible to just create a final output instantly and save it using FMOD? Or will I have to manually merge PCMS into one stream after all..
Thanks.
An important question here is why you need to save the files out, if it's possible to do this offline then it would be a lot simpler. If you must record the concatenation of several files (including others played in parallel), it is quite possible with FMOD.
One way would be to use wave-writer-nrt output mode, which allows you to output a wav file based on FMOD playsound calls in faster than realtime.
Another way is to use a custom DSP to access the data stream of any submix as it plays, useful if you want other sounds actually playing at the same time.
Another is simply create the sound objects, then use Sound::lock to access the PCM data, which you could concatenate yourself to a destination. Keep in mind all the sounds would need to be the same sample rate and channels, otherwise you would need to do processing. Also keep in mind you cannot do this for parallel sounds unless you want to mix the audio yourself.
I'm attempting to stream from a URL using Android's built in MediaPlayer class. However, I also need to send a special header along with the URL. Is this possible without having to rewrite the whole steaming process?
If it's not possible to send a header, I would need to stream the file manually. However, it appears that the MediaPlayer class locks the file you are writing to when it begins reading the file. This means you cant just simply continue writing to the file while reading from it. I've seen the 'double buffer' method however that results in choppy playback. Any suggestions?
I asked a question recently about alternatives to the double buffer method you mentioned:
is-there-a-better-way-to-save-streamed-files-with-mediaplayer
I guess you could act as a proxy in a thread, handle your header and forward the rest to the media player? Or if you control the server pass the extra data in a different request...
How to I create mediaplayer instance with inputstream?
I see only 4 function for setDataSource. And there is no function getting inputstream ?
is it a must to use FileDescriptor to mediaplayer ? It seems so basic. but, I couldnot find a way. In j2me, there is a function that Manager.createPlayer(InputStream). And you can use inputstream to create a media player. Is there a way to create a mediaplayer like j2me ?
How about making a HTTP server on the recieveing side (a thread on the phone) that outputs the data from the InputStream on any HTTP request to the OutputStream of the Socket and provide MediPlayer with URI http 127.0.0.1 : a port? THAT IS UGLY (but it should work)
it is also possible to play PCM uncompressed audio from an InputStream in android. goole it. if you can do decoding in software with JLayer or something and output it as PCMto the audio interface that should do the trick too but without hardware acceleration.
Pick your poison I guess. I chose option B.
One approach can be to write your stream to a File and then give it to the MediaPlayer for playback.
I'm looking into this right now (in order to send encrypted movie files to the MediaPlayer). Am I wrong in assuming the FileInputStream.getFD() is the solution to this? If you can get a FileDescriptor from a FileInputStream (unless you specifically need InputStream and not FileInputStream) then it seems like that can be passed right on to the MediaPlayer.
EDIT: Okay, so FileInputStream is created using a path or URL, making it useless.
You are correct, MediaPlayer will not take a stream parameter directly as its data source. The four overloaded versions of setDataSource() allow the data to come from a file (using the file path OR a FileDescriptor) or a Uri (web location or local content:// uri).
In addition, to static create() method can create a media player from a raw resource (R.raw.something) or the same style Uri as above.
Where are you sourcing the audio/video from other than either a file location or the web?
for now, I copy the InputStream to a temp file and give it to mediaplayer. but, you know, it s not good solution. because, it s slow solution. if data is big, player must wait too much.
my source is changing. for example, it s come from database. if I will not find solution, I convert my code to getting file. but, for now I desing the system to getting inputstream and play it. like, j2me function of MediaPlayer.createPlayer(InputStream,String)
I think you can get the file descriptor from your input stream and feed that to your setDataSource.