I'm using xamarin.android to create an android application. for working on the output of recorded audios in android for changing its pitch and the other thing with NWaves package, I need to change its format to .wav. I tried to use many audio convertors but all of them threw exceptions, but it should work with FFmpeg. However, I used this code but it doesn't generate any file.
List<string> cmd = new List<string>();
cmd.Add("ffmpeg");
cmd.Add("-i");
cmd.Add("/storage/emulated/0/Android/data/com.companyname.pushersvc/demo.3GP");
cmd.Add("/storage/emulated/0/Android/data/com.companyname.pushersvc/test.wav");
string cmdParams = string.Join(" ", cmd);
await FFMpeg.Xamarin.FFMpegLibrary.Run(
Application.Context,
cmdParams
);
return new FileInfo(path);
I read this and FFMpeg docs, but all of them used .mp4 convertor.
I also read ffmpeg doc for audio converting which you can see the code, which is not working
Related
I'm trying to implement Google Speech API in Android by following this demo: https://github.com/GoogleCloudPlatform/android-docs-samples
I was able to successfully reproduce the example in my app by using the given "audio.raw" file located in R.raw, and everything works perfectly. However, when I try to use my own audio files, it returns "API successful" without any transcription text. I'm not sure if it has to do with the files' path or the encoding, so I'll include information on both just in case.
Encoding
My audio files are obtained by recording a voice through MediaRecorder. These are the settings:
myAudioRecorder = new MediaRecorder();
myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_WB);
myAudioRecorder.setAudioSamplingRate(16000);
myAudioRecorder.setAudioEncodingBitRate(16000);
myAudioRecorder.setAudioChannels(1);
myAudioRecorder.setOutputFile(outputFile);
SpeechService's recognizeInputStream() function in the API:
mApi.recognize(
RecognizeRequest.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setEncoding(RecognitionConfig.AudioEncoding.AMR_WB) //originally it was LINEAR16
.setLanguageCode("en-US")
.setSampleRateHertz(16000)
.build())
.setAudio(RecognitionAudio.newBuilder()
.setContent(ByteString.readFrom(stream))
.build())
.build(),
mFileResponseObserver);
Encoding guidelines by Google: https://cloud.google.com/speech/docs/best-practices
From what I understand, I can use AMR_WB and 16kHz instead of the default LINEAR16, I'm just not sure if I'm doing it right.
Path
This is the example that is fully working (with the audio file from the repo):
mSpeechService.recognizeInputStream(getResources().openRawResource(R.raw.audio));
However, none of the following options work, even with the exact same file:
InputStream inputStream = new URL("[website]/test/audio.raw").openStream();
mSpeechService.recognizeInputStream(inputStream);
Neither:
Uri uri = Uri.parse("android.resource://[package]/raw/audio");
InputStream inputStream = getActivity().getContentResolver().openInputStream(uri); //"getActivity()" because this is in a Fragment
mSpeechService.recognizeInputStream(inputStream);
To be clear, the result on the above paths is the same as on my custom audio files: "API successful" with no transcription. One of the options I have tried for my custom audio files, with the same thing happening, is this:
FileInputStream fis = new FileInputStream(filePath);
mSpeechService.recognizeInputStream(fis);
The only reason I'm not 100% sure the problem is in the path is because if the API is returning with success, then the file was found in the specified path. The problem should be the encoding, but then it's weird that the same file ("audio.raw") sent in different ways produces different results.
Anyway, thank you in advance! :)
EDIT:
To be clear, it's not that it returns an empty string in the transcription. It just never enters the "onSpeechRecognized" function that also exists in the demo, so no transcription is given.
Investigating the Java code of the lib, I found no way to save playing video somewhere. However, the VLC core has such capabilities, according to this doc, you can duplicate the stream and save it, redirecting it right to the file.
I thought we could supply the corresponding arguments while creating an instance of lib, so I tried to add an option when initializing library in libvlcjni.c like that:
"--sout=duplicate{dst=standard{access=file,mux=ts,dst=/storage/emulated/0/example.mp4},
dst=display}"
but seems it's not working. Any other ideas?
You can concurrently save a playing video to a file using libvlc (at least the following worked for me):
final ArrayList<String> args = new ArrayList<>();
args.add("-vvv");
mLibVLC = new LibVLC(this, args);
mMediaPlayer = new MediaPlayer(mLibVLC);
<code associating surface for display...>
Media media = new Media(mLibVLC, Uri.parse(SAMPLE_URL));
media.addOption(":sout=#duplicate{dst=file{dst=" + <file name> + "},dst=display}");
mMediaPlayer.setMedia(media);
mMediaPlayer.play();
Guess, currenty there is no way to do it by means of libvlc.
However, guys have plans for this feature, see their milestones at gitlab
I'm using mp4parser to mux h264 and aac file which are re-encoded from orginal video file,how can I write the metadata of the original video to the new mp4 file? Or is there a common method to write metadata to mp4 file?
metadata and MP4 is a really problem. There is no generally supported specification. But this is only one part of the problem.
Prob (1): When to write metadata
Prob (2): What to write
Prob (1) is relatively easy to solve: Just extend the DefaultMp4Builder or the FragmentedMp4Builder on your own and override the
protected ParsableBox createUdta(Movie movie) {
return null;
}
with something meaningful. E.g.:
protected ParsableBox createUdta(Movie movie) {
UserDataBox udta = new UserDataBox();
CopyrightBox copyrightBox = new CopyrightBox();
copyrightBox.setCopyright("All Rights Reserved, me, myself and I, 2015");
copyrightBox.setLanguage("eng");
udta.addBox(copyrightBox);
return udta;
}
some people used that to write apple compatible metadata but even though there are some classes in my code I never really figured out what works and what not. You might want to have a look into Apple's specification here
And yes: I'm posting this a year to late.
It seems that the 'mp4parser' library (https://code.google.com/p/mp4parser/), supports writing Metadata to mp4 files in Android. However, I've found there's little-to-no documentation on how to do this, beyond a few examples in their codebase. I've had some luck with the following example, which writes XML metadata into the 'moov/udta/meta' box:
https://github.com/copiousfreetime/mp4parser/blob/master/examples/src/main/java/com/googlecode/mp4parser/stuff/ChangeMetaData.java
If you consider the alternatives you might want to look at JCodec for this purpose. It now has the org.jcodec.movtool.MetadataEditor API (and a matching CLI org.jcodec.movtool.MetadataEditorMain).
Their documentation contains many samples: http://jcodec.org/docs/working_with_mp4_metadata.html
So basically when you want to add some metadata you need to know what key(s) it corresponds to. One way to find out is to inspect a sample file that already has the metadata you need. For this you can run the JCodec's CLI tool that will just print out all the existing metadata fields (keys with values):
./metaedit <file.mp4>
Then when you know the key you want to work with you can either use the same CLI tool:
# Changes the author of the movie
./metaedit -f -si ©ART=New\ value file.mov
or the same thing via the Java API:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<Integer, MetaValue> meta = mediaMeta.getItunesMeta();
meta.put(0xa9415254, MetaValue.createString("New value")); // fourcc for '©ART'
mediaMeta.save(false); // fast mode is off
To delete a metadata field from a file:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<Integer, MetaValue> meta = mediaMeta.getItunesMeta();
meta.remove(0xa9415254); // removes the '©ART'
mediaMeta.save(false); // fast mode is off
To convert string to integer fourcc you can use something like:
byte[] bytes = "©ART".getBytes("iso8859-1");
int fourcc =
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
If you want to edit/delete the android metadata you'll need to use a different set of fucntion (because it's stored differently than iTunes metadata):
./metaedit -sk com.android.capture.fps,float=25.0 file.mp4
OR alternatively the same through the API:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<String, MetaValue> meta = mediaMeta.getKeyedMeta();
meta.put("com.android.capture.fps", MetaValue.createFloat(25.));
mediaMeta.save(false); // fast mode is off
I am working on a project in Flash Mobile using ActionScript. I have a zipped wav file that I need to be able to de serialize and play as needed in a Button Press action. Below is the code for zipping the wav file.
mic.removeEventListener(SampleDataEvent.SAMPLE_DATA, micSampleDataHandler);
btnRecord.setStyle("icon", recOff);
sampleCount++;
// save the raw PCM samples as a bare WAV file
var wav:ByteArray = new ByteArray();
var writer:WAVWriter = new WAVWriter();
writer.numOfChannels = 1;
writer.sampleBitRate = 16;
writer.samplingRate = 11025;
samples.position = 0;
writer.processSamples(wav, samples, 11025, 1);
wav.position = 0;
// zip the WAV file
var fzip:FZip = new FZip();
fzip.addFile(name + sampleCount.toString(), wav);
var zip:ByteArray = new ByteArray();
fzip.serialize(zip);
var recSpot:Object = {
id: null,
audio: zip,
name: "New Audio File " + newRecNum,
existsdb: "false"
};
newRecNum++;
recordings.addItem(recSpot);
}
What can I do to play this file, really haven't had to play a zipped file before.
I'm not familiar with WAVWriter (which is probably somewhat beside the point), but here's what I do know.
Firstly, because of the nature of a compression, you cannot (as far as I know) play a zipped audio file, period. You will need to unzip it first.
A quick Google search turned up THIS AS3 TUTORIAL on unzipping with FZIP. The example program is using .PNGs, but I would assume you can adjust it to work with the raw .WAV file you zipped earlier. Skip down to Step 5 for the actual code. (You'll need to rewrite it to work with your interface, obviously.)
You won't need the DataProvider variable in step 5, as that is for components, specifically. You'll need to load your data into something else. If your method of playing WAV files is anything like mine (I use the as3WAVSound class), you'll probably want to load the data into a ByteArray and play off of that.
You also probably won't need the for loop he uses in step 10, as your code appears to be creating a ZIP with only one WAV file. That simplifies things considerably.
Anyway, I hope that answers your question!
I have this question: how can I load, in Android, a video file stored in my device, and how can I split it into frames?
I'm using IntelliJ and I want to split the video into frames in order to process them with some image processing techniques (with OpenCv for Android library).
You don't strictly need to use OpenCV for this. You can use the MediaMetaDataRetreiver class provided by the SDK. It provides methods to extract metadata from all kinds of media files. You can try something like:
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(file.getAbsolutePath());
imgView.setImageBitmap(retriever.getFrameAtTime(TIME_OFFSET,MediaMetadataRetriever.OPTION_CLOSEST));
where TIME_OFFSET is in microseconds.
Grabbing a video frame in OpenCV is pretty easy. There are lots of examples on OpenCV site. However crucial thing is to set-up opencv on andriod. You can follow this link on getting started with Opencv on andriod.
http://opencv.org/android
Once you have opencv installed on andriod. You can easily load video file and grab frame in Mat structure and then do some processing on it.
Here is the sample one. It will need some modification to run it on andriod. I think you will need to used NDK on andriod for this.
int main(int argc, char*argv[])
{
char *my_file = "C:\\vid_an2\\desp_me.avi";
std::cout<<"Video File "<<my_file<<std::endl;
cv::VideoCapture input_video;
if(input_video.open(my_file))
{
std::cout<<"Video file open "<<std::endl;
}
else
{
std::cout<<"Not able to Video file open "<<std::endl;
}
namedWindow("My_Win",1);
namedWindow("Segemented", 1);
Mat cap_img;
for(;;)
{
input_video >> cap_img;
imshow("My_Win", cap_img);
waitKey(0);
}
return 0;
}