i am trying to capture video on android using v4l2 under jni. i found some guide and followed the step:
fd = open("/dev/video0", O_RDWR);
/* init part */
ioctl(fd, VIDIOC_QUERYCAP, &caps);
ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc);
ioctl(fd, VIDIOC_S_FMT, &fmt);
ioctl(fd, VIDIOC_REQBUFS, &req);
ioctl(fd, VIDIOC_QUERYBUF, &buf);
ioctl(fd, VIDIOC_QBUF, &buf);
/* capture part */
FILE *fp = fopen("/sdcard/img.yuv", "wb");
for (i = 0; i < 20; i++)
{
ioctl(fd, VIDIOC_DQBUF, &buf);
fwrite(buffers[buf.index].start, 1, buf.bytesused, fp);
ioctl(fd, VIDIOC_QBUF, &buf);
}
fclose(fp);
this is the main structure of my code. all the function run correctly and return 0. however, when i open the output file with binary viewer, i found that all the data is 0.
is there any problem with my code? i got confused because all the functions returned 0.
Thanks!!
You are using an array called buffers[]. But I can't see where it's declared or what it stands for. If there is no code missing above, you will always get zeros cause you are writing buffer[] to the file and not the stuff you get from v4l2.
Further more, the initial values of caps, fmtdesc, fmt, req and buf prior to the ioctl command would be interesting too. Depending on their inital values, you will have different communication interfaces. Issues could be hidden in these parts.
As you wrote in your question, all ioctl commands would return 0, there should be no error. If everything behaves as expected. Another way to check for issues is calling
perror("<your comment or hint to line above>");
after each ioctl command. This would print you more information about errors on your std-out. ( more details about perror can be found in this thread When should I use perror("...") and fprintf(stderr, "...")?)
Are you trying to get the images from the camera? (on some phones video0 you used above is the back cam) On some android devices the camera has to be started by complex procedure using other device drivers besides videoXY. And trying to get the images from video0 while the official camera app is running might be difficult. The official v4l2 api says:
V4L2 drivers should not support multiple applications reading or writing the same data stream on a device by copying buffers, time multiplexing or similar means. This is better handled by a proxy application in user space.
From: http://linuxtv.org/downloads/v4l-dvb-apis/common.html#idp18553208
Can you post more (detailed) code? I might be able to help, as I'm doing very similar stuff.
To be able to reproduce it, it would be very interesting with which android device you are working (type / model number / android version).
Related
I have a problem with the Android AudioRecord library.
I need to record an audio stream from the device's microphone.
The initialization of the class is as follows:
recorder = new AudioRecord(
currentAudioSource,
SAMPLE_RATE_IN_8KHZ,
CHANNEL, // Mono
ENCODING, // ENCODING_PCM_16BIT
bufferSize // 2048
);
Then, I call recorder.startRecording() to make the audio stream active.
And to acquire this flow I call the method in a loop:
recorder.read(samples, 0, currentBufferSize)
The variable samples is a short[] and currentBufferSize is the lenght of the buffer.
The "read" method works correctly for the first N loop.
At loop N + 1, the method is stuck waiting to give me back 2048 short, until I call the stopRecording which gives me the registered values (less than 2048 short).
On the next registration, the read method returns me an empty short [] and the error code "-1" (general error).
It's been a few days since I got it right, also because the error does not occur in a systematic way, but randomly on multiple devices.
Do you have any ideas to resolve this situation?
Thank you
I solved with this solution:
while(runWorker) {
if (recorder != null && recorder.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
...
Thread.sleep(40);
sampled = this.recorder.read(samples, 0, currentBufferSize, AudioRecord.READ_NON_BLOCKING);
...
I inserted a 40 ms pause and used the non-blocking Read.
This works on all devices except some Samsung tablets. This is the related post: AudioRecord.read with read mode: READ_NON_BLOCKING not working on Tablet Samsung
On Samsung tablets, the non-blocking Read always returns the value 0, as if it were not recording audio. If I use AudioRecord.READ_BLOCKING it works correctly.
Do you have any ideas about it?
Thanks.
Michele
I'm working on a DSP project on Android which requires low latency audio I/O. For this reason, I'm using Oboe library. In the LiveEffect example, the synchronous recording and playback is demonstrated. However, for acoustic feedback neutralization, I need the other way around, that is to generate White Noise signal through a built-in speaker first, then record it using a mic. I tried to modify LiveEffect example using this asked question, i.e setting the recording stream as Master (callback) and using non-blocking write method for the playback stream. But I got the following error when I run my code on Pixel XL (Android 9.0):
D/AudioStreamInternalCapture_Client: processDataNow() wait for valid timestamps
D/AudioStreamInternalCapture_Client: advanceClientToMatchServerPosition() readN = 0, writeN = 384, offset = -384
--------- beginning of crash
A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x5800003f666c66 in tid 2852 (AAudio_1), pid 2796 (ac.oiinitialize)
Here is my callback:
oboe::DataCallbackResult
AudioEngine::onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) {
assert(oboeStream == mRecordingStream);
int32_t framesToWrite = mPlayStream->getFramesPerBurst();
oscillator_->whiteNoise(framesToWrite); // write white noise into buffer;
oboe::ResultWithValue<int32_t> result = mPlayStream->write(oscillator_->write(), framesToWrite, 0);
// oscillator_->write() returns const void* buffer;
if (result != oboe::Result::OK) {
LOGE("input stream read error: %s", oboe::convertToText(result.error()));
return oboe::DataCallbackResult ::Stop;
}
// add Adaptive Feedback Neutralization Algorithm here....
return oboe::DataCallbackResult::Continue;
}
Is my approach correct for generating a signal and then capturing it through a mic? If so, can anyone help me with this error? Thank you in advance.
However, for acoustic feedback neutralization, I need the other way around, that is to generate White Noise signal through a built-in speaker first, then record it using a mic
You can still do this using an output stream callback and a non-blocking read on the input stream. This is the more common (and tested) way of doing synchronous I/O. A Larsen effect will work fine this way.
Your approach should still work, however, I'd stick to the LiveEffect way of setting up the streams since it works.
In terms of your error SIGSEGV usually means a null pointer dereference - are you starting your input stream before the output stream? This could meant you're attempting to write to the output stream which hasn't yet been opened.
I want to control a ptz camera from android,actually i do that in jni and use linux api,the camera is connected to android-tvbox's usb interface directly, ,below is the code:
struct v4l2_ext_control xctrls[1];
struct v4l2_ext_controls ctrls;
memset(xctrls, 0, sizeof xctrls);
memset(&ctrls, 0, sizeof ctrls);
xctrls[0].id = V4L2_CID_PAN_ABSOLUTE;
xctrls[0].value = 20;
ctrls.ctrl_class = V4L2_CTRL_CLASS_CAMERA;
ctrls.count = 1;
ctrls.controls = xctrls;
//xioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
int result = ioctl(fd, VIDIOC_S_CTRL, &ctrls);
//LOGE("Cannot identify:%d , %d, %s", result, errno, strerror (errno));
LOGE("Cannot open '%d': %d, %s", result, errno, strerror (errno));
and it return invalid argument , can anyone tell me which argument is wrong?Or my code is incorrect...
I have solved this problem. Actually, you need to design your Android source code in UVC (USB Video Class) module, and UVC is located in the kernel of the whole android source code.
What's more, you have to cooperate with the camera's vendor, because they have deep insights into the firmware of PTZ cameras, and Android's UVC version should apply to camera firmware, data length and control type (absolute or relative).
Furthermore, Android kernel's version is generally 3.10. When you control camera with absolute control, it may move in one direction but not another one, because the Android UVC control parameters of absolute is unsigned: you should change it to signed parameters.
When you control in relative, it's a little more complicated, for you should add relative control in Android source code because Android kernel in 3.10 does not support it. You can get the Linux kernel patch to add relative movements.
The video decoding code of an app is typical, just like the example code in the MediaCodec document. Nothing special. The configuration statement is like the following:
myMediaCodec.configure(myMediaFormat, mySurface, null, 0);
Everything works fine. However, if I change the above code to the following to decode the video to a buffer instead of a surface:
myMediaCodec.configure(myMediaFormat, null, null, 0);
then the following code:
int iOutputBufferIndex = myMediaCodec.dequeueOutputBuffer(myBufferInfo, 100000);
will always return MediaCodec.INFO_TRY_AGAIN_LATER. Even more strangly, any subsequent call of myMediaCodec.stop() or myMediaCodec.release() will hang (i.e. the call never returns or generates an exception).
This happens on a generic (AGPTek) tablet (Allwinner A31S, 1.5GHz Cortex A7 Quad Core). On a simulator and another tablet (Asus Memo Pad), everything works fine.
I am asking for any tip to help get around this problem.
Do you provide one single input buffer worth of data before trying this, or do you pass as many packets as you can before dequeueInputBuffer also blocks or returns INFO_TRY_AGAIN_LATER? A decoder might not output data after only one packet of input (if the decoder has got some delay), but if it works with Suface output it should probably behave in the same way there.
If that (queueing as many input buffers as possible) doesn't work, I would say that this sounds like a decoder bug.
I have been trying to capture audio, within a native linux program running on an Android device via adb shell.
Since I seemed to be getting only (very quiet) noise, i.e. no actual signal (interestingly, an Android/Java program doing similar did show there was a signal on that input),
I executed alsa_amixer, which had one entry that looked like the right one:
Simple mixer control 'Capture',0
Capabilities: cvolume cswitch penum
Capture channels: Front Left - Front Right
Limits: Capture 0 - 63
Front Left: Capture 31 [49%] [0.00dB] [off]
Front Right: Capture 31 [49%] [0.00dB] [off]
"off". That would explain the noise.
So I looked for examples of how to use alsa_amixer to unmute the channels, I found different suggestions for parameters like "49% on" or "49% unmute", or just "unmute" none of which works. (if the volume% is left out, it says "Invalid command!", otherwise, the volume is set, but the on/unmute is ignored)
I also searched how to do this programatically (which I'll ultimately need to do, although the manual approach would be helpful for now), but wasn't too lucky there.
The only ALSA lib command I found which sounds like it could do something like that was "snd_mixer_selem_set_capture_switch_all", but the docs don't day what the parameter does (1/0 is not on/off, I tried that ;) )
The manual approach to set these things via alsa_amixer does work - but only if android is built with the 'BoardConfigCommon.mk' modified, at the entry: BOARD_USES_ALSA_AUDIO := false, instead of true.
Yeah, this will probably disable ALSA for android, which is why it wouldn't meddle with the mixer settings anymore.
To you android programmers out there, note that this is a very niche use case of course, as was to be expected by my original post to begin with.
This is not what most people would want to do.
I just happen to tinker with an android device here in unusual ways ;-)
Just posting the code as question giver suggested, also don't like external links.
#include <alsa/asoundlib.h>
int main()
{
snd_mixer_t *handle;
snd_mixer_selem_id_t *sid;
snd_mixer_open(&handle, 0);
snd_mixer_attach(handle, "default");
snd_mixer_selem_register(handle, NULL, NULL);
snd_mixer_load(handle);
snd_mixer_selem_id_alloca(&sid);
snd_mixer_selem_id_set_index(sid, 0);
snd_mixer_selem_id_set_name(sid, "Capture");
snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
snd_mixer_selem_set_capture_switch_all(elem, 0);
snd_mixer_selem_set_capture_dB_all(elem, 0, 0);
snd_mixer_close(handle);
}