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;
}
}
}
}
The output video is tiled, as shown in the image below:
Steps to Reproduce:
Set up the encoder using the SetupEncoder method with the specified width, height, and output path.
Feed frames to the encoder using the EncodeFrame method.
Observe the saved video file.
Questions:
Why is the output video tiled?
What changes are needed in my code to fix this issue and produce a normal video?
Any help or suggestions would be greatly appreciated. Thank you!
1