I am using JCODEC to create a video of my screen activities. I don’t want to use android NDK as I want to do it in JAVA. I am running a for loop to encode images using SequenceEncoder. The problem is the loop is taking too long to run and log cat gives messages of GC_FOR_ALLOC freed. For even 5 iterations the loop takes many seconds. So I am unable to take proper video of my activities. I tried to make changes in the code but its not helping. Please help me with this. Suggest other options if available. Thanks in advance.
File file = new File(Environment.getExternalStorageDirectory()+"/a.mp4");
SequenceEncoder encoder = new SequenceEncoder(file);
mview.setDrawingCacheEnabled(true);
// only 5 frames in total
for (int i = 1; i <= 5; i++) {
// getting bitmap from drawable path
mview.postInvalidate();
encoder.encodeNativeFrame(this.fromBitmap(mview.getDrawingCache()));
}
encoder.finish();
Related
I need to send text to server, get wav streaming data (Base64 form and locally converting to byteArray), save and play the files. As retrofit cannot process larger than around 5 million characters I am splitting the text into pieces and getting the several wav streaming data. Now my target is to save the fetched multiple wav data into one file and play further.
But the problem is when I am concatenating the stream data(byteArray), the files playing the first one only. I googled and searched in SO for solutions but it is not working at all. what could be the reason(could be for header issue and I tried skipping first 44 length from 2nd one).
this is how tried
if (count == 0)
allByteArray += clipData
else
allByteArray += clipData.copyOfRange(44,clipData.size)
count += 1
return until all arrayByte
val output = FileOutputStream(file,true)
output.write(allByteArray)
output.close()
I solved the issue.
I have just updated the file size in header(sum of all files size replaced to index 40-43)
I have multiple audio files converted into byte array for each, and i have start time and end time of each audio file (these audio files are converted from video so i have its time stamps).
Now i want to merge these byte array of audio files to create one single audio mp3 file. I tried to simply merge these two array and it successfully creates a single mp3 file but it doesn't have any pause in between.
I want to add silent audio between each file based on the difference of start time and end time of each file. To achieve that, i added 0 bytes for each second difference between each array but it doesn't add sufficient pause.
Is there any way to determine how many bytes it will require to add for each second?
Every audio has 8000 sample Rate Hertz.
Following is the code i am using to add 0 bytes.
ArrayList<Byte> buffer = previousTranslation.getAudioBuffer();
// to get gape in seconds between two audio files from a video
int diff = (int)differenceBetweenTwoCalendar(
previousTranslation.getSentenceEndTime(),
translation.getSentenceStartTime());
// Add 0 bytes for each second between two audio buffers(bytes array)
for(int j = 0; j < diff; j++)
buffer.add((byte) 0);
// Add seconds part of audio buffer byte array
buffer.addAll(translation.getAudioBuffer();
I want to save the video every 5 seconds while the video recording is ON.
I have tried many solutions but I am facing a Glitch that is, the Last Saved Frame remains in preview for around 300ms.
I think the reason is in MediaRecorder class "Once a recorder has been stopped, it will need to be completely reconfigured and prepared before being restarted."
Thanks
I think it's impossible to do that with MediaRecorder. The better approach could be encoding video by using MediaCodec and storing encoded content bt using MediaMuxer.
Grafika is a project on Google Github account which is a dumping ground for Android graphics & media hacks. In this project, you can find good examples of using both MediaCodec and MediaMuxer classes.
I forked the Grafika project and did some modifications to support sequential segmented recording. You can find it here. When you run the application, select Show + capture camera item from the list and then set Output Segment Duration for example to 5 and then press Start recording button.
Please look at VideoEncoderCore and CameraCaptureActivity classes source code to find how it works. You can find here how it segments live camera feed to different files.
"I think the reason is in MediaRecorder class, "Once a recorder has been stopped, it will need to be completely reconfigured and prepared before being restarted"."
You can use multiple mediaMuxer's to encode separate files.
The camera should send data to fill a MediaMuxer object (which itself produces an .mp4 file).
When needed, you can start writing the Camera data to a second (different) MediaMuxer thus automatically creating a second new .mp4 file (on begin usage of the muxer).
The first MediaMuxer can then close and save its file. Your first segment is ready...
If needed, try to study this code for a guide on using Camera with mediaMuxer:
https://bigflake.com/mediacodec/CameraToMpegTest.java.txt
So you have a function that handles things when the 5 second interval has passed? In that function, could cycle the recording between two muxers, giving one a chance to close its file, while the other records the next segment and then vice-versa).
Instead of something like below (using MediaRecorder.OutputFormat.MPEG_4):
this.mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
You will instead create a new muxer (with MUXER_OUTPUT_MPEG_4):
//# create a new File to ssave into
File outputFile = new File(OUTPUT_FILENAME_DIR, "/yourFolder/Segment" + "-" + mySegmentNum + ".mp4");
String outputPath = outputFile.toString();
int format = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
try { mMuxer = new MediaMuxer(outputPath, format); }
catch (IOException e) { Log.e(TAG, e.getLocalizedMessage()); }
And you stop a muxer with:
mMuxer1.stop(); mMuxer1.release();
PS:
Another option is to use Threads to run multiple MediaRecorders. It might help your situation. See the Android Background Process guide.
I recorded a Video for limited time. Now i want to fetch all frames of video. I am using the below code and by using it i am able to get frames but i am not getting all video frames. 3 to 4 frames are repeated then i got a different frame. But as we all know we can get 25- 30 frames in a second to display smooth video. How to get all frames.
for (int i = 0; i < 30; i++) {
Bitmap bArray = mediaMetadataRetriever.getFrameAtTime(
1000000 * i,
MediaMetadataRetriever.OPTION_CLOSEST);
savebitmap(bArray, 33333 * i);
}
I don't want to use NDK. I got this link don't know what should be the value for "argb8888". I am getting error here. Can anyone explain how to do it.
Getting frames from Video Image in Android
I faced the same problem before and the Android's MediaMetadataRetriever seems not appropriated for this task since it doesn't have a good precision.
I used a library called "FFmpegMediaMetadataRetriever" in android studio:
Add this line in your build.graddle under module app:
compile 'com.github.wseemann:FFmpegMediaMetadataRetriever:1.0.14'
Rebuild your project.
Use the FFmpegMediaMetadataRetriever class to grab frames with higher
precision:
FFmpegMediaMetadataRetriever med = new FFmpegMediaMetadataRetriever();
med.setDataSource("your data source");
and in your loop you can grab frame using:
Bitmap bmp = med.getFrameAtTime(i*1000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
To get image frames from video we can use ffmpeg.For integrating FFmpeg in android we can use precompiled libraries like ffmpeg-android.
To extract image frames from a video we can use below command
String[] complexCommand = {"-y", "-i", inputFileAbsolutePath, "-an",
"-r", "1/2", "-ss", "" + startMs / 1000, "-t", "" + (endMs - startMs)
/ 1000, outputFileAbsolutePath};
Here,
-y
Overwrite output files
-i
ffmpeg reads from an arbitrary number of input “files” specified by the -i option
-an
Disable audio recording.
-r
Set frame rate
-ss
seeks to position
-t
limit the duration of data read from the input file
Here in place of inputFileAbsolutePath you have to specify the absolute path of video file from which you want to extract images.
For complete code check out this on my repository .Inside extractImagesVideo() method I am running command for extracting images from video.
For complete tutorial regarding integration of ffmpeg library and using ffmpeg commands to edit videos, check out this post which I have written on my blog.
You need to do :
Decode the video.
Present the decoded images at least as fast as 24 images / second. I
suppose you can skip this step.
Save the decoded images.
It appears that decoding the video would be the most challenging step. People and companies have spent years developing codecs (encoder / decoder) for various video formats.
Use this library JMF for FFMPEG.
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;
}