Video Recorder using MediaCodec in Xamarin.Android Produces Tiled Video Output
Gurucharan Vijayakumar
0
Reputation points
I am working on a video recording feature in a Xamarin.Android app using MediaCodec for encoding. My goal is to record video and save it in H.264 format. However, the output video appears tiled, as shown in the image below.
Here is my code:
using Android.Media;
using Android.Util;
using Java.IO;
using Java.Nio;
using System;
using System.IO;
using static Android.Media.MediaCodec;
namespace Record.Droid
{
public class VideoRecorder
{
private const string TAG = "VideoRecorder";
private const string MIMETYPE = "video/avc";
private const int WAITTIME = 10000; // Adjust as needed
private MediaCodec codec;
private DataOutputStream dos;
public bool SetupEncoder(int width, int height, string outputPath)
{
try
{
try
{
FileStream fileStream = new FileStream(outputPath, FileMode.Create);
dos = new DataOutputStream(fileStream);
}
catch (System.IO.IOException e)
{
Log.Error(TAG, "Failed to open output file: " + e.Message);
return false;
}
MediaFormat mediaFormat = MediaFormat.CreateVideoFormat(MIMETYPE, width, height);
mediaFormat.SetInteger(MediaFormat.KeyBitRate, 700000);
mediaFormat.SetInteger(MediaFormat.KeyFrameRate, 30);
mediaFormat.SetInteger(MediaFormat.KeyColorFormat, (int)MediaCodecCapabilities.Formatyuv420planar);
mediaFormat.SetInteger(MediaFormat.KeyIFrameInterval, 5);
codec = MediaCodec.CreateEncoderByType(MIMETYPE);
codec.Configure(mediaFormat, null, null, MediaCodecConfigFlags.Encode);
codec.Start();
return true;
}
catch (System.IO.IOException e)
{
Log.Error(TAG, "Failed to set up encoder: " + e.Message);
ReleaseEncoder();
return false;
}
}
public void EncodeFrame(byte[] data, long presentationTimeUs)
{
try
{
ByteBuffer[] inputBuffers = codec.GetInputBuffers();
ByteBuffer[] outputBuffers = codec.GetOutputBuffers();
bool sawInputEOS = false;
int inputBufferIndex = -1, outputBufferIndex = -1;
BufferInfo info = new BufferInfo();
inputBufferIndex = codec.DequeueInputBuffer(WAITTIME);
if (inputBufferIndex >= 0)
{
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.Clear();
inputBuffer.Put(data);
codec.QueueInputBuffer(inputBufferIndex, 0, data.Length, presentationTimeUs, 0);
}
outputBufferIndex = codec.DequeueOutputBuffer(info, WAITTIME);
if (outputBufferIndex >= 0)
{
ByteBuffer outputBuffer = codec.GetOutputBuffer(outputBufferIndex).Duplicate();
outputBuffer.Position(info.Offset);
outputBuffer.Limit(info.Offset + info.Size);
byte[] array = new byte[info.Size];
outputBuffer.Get(array);
dos.Write(array);
codec.ReleaseOutputBuffer(outputBufferIndex, false);
if ((info.Flags & MediaCodecBufferFlags.EndOfStream) != 0)
{
ReleaseEncoder();
}
}
}
catch (System.IO.IOException e)
{
Log.Error(TAG, "Error encoding frame: " + e.Message);
}
}
public void ReleaseEncoder()
{
try
{
if (dos != null)
{
dos.Flush();
dos.Close();
}
}
catch (System.IO.IOException e)
{
Log.Error(TAG, "Failed to release encoder: " + e.Message);
}
if (codec != null)
{
codec.Stop();
codec.Release();
codec = null;
}
}
}
}
Sign in to answer