还有另一种方法可以将 ffmpeg 中的帧导出到 texture2d 吗?我的代码在 Windows 但不在 Linux
Is there another way to export a frame in ffmpeg to a texture2d? My code working in Windows but not Linux
声音在 Linux 中的工作方式与在 Windows 中一样。但是视频只是一个黑屏,当我尝试将帧保存为 BMP 文件时,所有这些都是 corrupt/empty 文件。我正在使用 Ffmpeg.Autogen 与库交互。 https://github.com/Ruslan-B/FFmpeg.AutoGen。该文件是 MKV 容器中的 VP8 和 OGG。尽管出于某种原因扩展名是 AVI。
我试着打乱了代码的顺序。我检查以确保在 Linux 上构建的 Ffmpeg 具有 VP8。我在网上搜索,但找不到另一种方法来做我正在做的事情。这是为了对 OpenVIII 项目做出贡献。我的叉子-> https://github.com/Sebanisu/OpenVIII
这只是准备缩放器更改像素格式,否则人们的脸是蓝色的。
private void PrepareScaler()
{
if (MediaType != AVMediaType.AVMEDIA_TYPE_VIDEO)
{
return;
}
ScalerContext = ffmpeg.sws_getContext(
Decoder.CodecContext->width, Decoder.CodecContext->height, Decoder.CodecContext->pix_fmt,
Decoder.CodecContext->width, Decoder.CodecContext->height, AVPixelFormat.AV_PIX_FMT_RGBA,
ffmpeg.SWS_ACCURATE_RND, null, null, null);
Return = ffmpeg.sws_init_context(ScalerContext, null, null);
CheckReturn();
}
将帧转换为 BMP
我在想这就是问题所在。因为我已经添加了 bitmap.save 并且得到了空的 BMP。
public Bitmap FrameToBMP()
{
Bitmap bitmap = null;
BitmapData bitmapData = null;
try
{
bitmap = new Bitmap(Decoder.CodecContext->width, Decoder.CodecContext->height, PixelFormat.Format32bppArgb);
AVPixelFormat v = Decoder.CodecContext->pix_fmt;
// lock the bitmap
bitmapData = bitmap.LockBits(new Rectangle(0, 0, Decoder.CodecContext->width, Decoder.CodecContext->height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte* ptr = (byte*)(bitmapData.Scan0);
byte*[] srcData = { ptr, null, null, null };
int[] srcLinesize = { bitmapData.Stride, 0, 0, 0 };
// convert video frame to the RGB bitmap
ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize); //sws_scale broken on linux?
}
finally
{
if (bitmap != null && bitmapData != null)
{
bitmap.UnlockBits(bitmapData);
}
}
return bitmap;
}
获得位图后,我们将其转换为 Texture2D,以便绘制它。
public Texture2D FrameToTexture2D()
{
//Get Bitmap. there might be a way to skip this step.
using (Bitmap frame = FrameToBMP())
{
//string filename = Path.Combine(Path.GetTempPath(), $"{Path.GetFileNameWithoutExtension(DecodedFileName)}_rawframe.{Decoder.CodecContext->frame_number}.bmp");
//frame.Save(filename);
BitmapData bmpdata = null;
Texture2D frameTex = null;
try
{
//Create Texture
frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, frame.Width, frame.Height, false, SurfaceFormat.Color); //GC will collect frameTex
//Fill it with the bitmap.
bmpdata = frame.LockBits(new Rectangle(0, 0, frame.Width, frame.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);// System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte[] texBuffer = new byte[bmpdata.Width * bmpdata.Height * 4]; //GC here
Marshal.Copy(bmpdata.Scan0, texBuffer, 0, texBuffer.Length);
frameTex.SetData(texBuffer);
}
finally
{
if (bmpdata != null)
{
frame.UnlockBits(bmpdata);
}
}
return frameTex;
}
}
我可以 post 更多,如果你想要它几乎都在我的叉子上
视频将像在 Windows 中一样播放。可以达到 15 fps 的流畅度。 :)
我最终删除了代码的位图部分。它奏效了!所以之前我会将帧转换为位图,然后它将像素从位图中复制到 Texture2D 中。我仔细观察,意识到我可以跳过位图的那一步。很抱歉我的问题不够清楚。
/// <summary>
/// Converts Frame to Texture
/// </summary>
/// <returns>Texture2D</returns>
public Texture2D FrameToTexture2D()
{
Texture2D frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, Decoder.CodecContext->width, Decoder.CodecContext->height, false, SurfaceFormat.Color);
const int bpp = 4;
byte[] texBuffer = new byte[Decoder.CodecContext->width * Decoder.CodecContext->height * bpp];
fixed (byte* ptr = &texBuffer[0])
{
byte*[] srcData = { ptr, null, null, null };
int[] srcLinesize = { Decoder.CodecContext->width * bpp, 0, 0, 0 };
// convert video frame to the RGB data
ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize);
}
frameTex.SetData(texBuffer);
return frameTex;
}
声音在 Linux 中的工作方式与在 Windows 中一样。但是视频只是一个黑屏,当我尝试将帧保存为 BMP 文件时,所有这些都是 corrupt/empty 文件。我正在使用 Ffmpeg.Autogen 与库交互。 https://github.com/Ruslan-B/FFmpeg.AutoGen。该文件是 MKV 容器中的 VP8 和 OGG。尽管出于某种原因扩展名是 AVI。
我试着打乱了代码的顺序。我检查以确保在 Linux 上构建的 Ffmpeg 具有 VP8。我在网上搜索,但找不到另一种方法来做我正在做的事情。这是为了对 OpenVIII 项目做出贡献。我的叉子-> https://github.com/Sebanisu/OpenVIII
这只是准备缩放器更改像素格式,否则人们的脸是蓝色的。
private void PrepareScaler()
{
if (MediaType != AVMediaType.AVMEDIA_TYPE_VIDEO)
{
return;
}
ScalerContext = ffmpeg.sws_getContext(
Decoder.CodecContext->width, Decoder.CodecContext->height, Decoder.CodecContext->pix_fmt,
Decoder.CodecContext->width, Decoder.CodecContext->height, AVPixelFormat.AV_PIX_FMT_RGBA,
ffmpeg.SWS_ACCURATE_RND, null, null, null);
Return = ffmpeg.sws_init_context(ScalerContext, null, null);
CheckReturn();
}
将帧转换为 BMP 我在想这就是问题所在。因为我已经添加了 bitmap.save 并且得到了空的 BMP。
public Bitmap FrameToBMP()
{
Bitmap bitmap = null;
BitmapData bitmapData = null;
try
{
bitmap = new Bitmap(Decoder.CodecContext->width, Decoder.CodecContext->height, PixelFormat.Format32bppArgb);
AVPixelFormat v = Decoder.CodecContext->pix_fmt;
// lock the bitmap
bitmapData = bitmap.LockBits(new Rectangle(0, 0, Decoder.CodecContext->width, Decoder.CodecContext->height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte* ptr = (byte*)(bitmapData.Scan0);
byte*[] srcData = { ptr, null, null, null };
int[] srcLinesize = { bitmapData.Stride, 0, 0, 0 };
// convert video frame to the RGB bitmap
ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize); //sws_scale broken on linux?
}
finally
{
if (bitmap != null && bitmapData != null)
{
bitmap.UnlockBits(bitmapData);
}
}
return bitmap;
}
获得位图后,我们将其转换为 Texture2D,以便绘制它。
public Texture2D FrameToTexture2D()
{
//Get Bitmap. there might be a way to skip this step.
using (Bitmap frame = FrameToBMP())
{
//string filename = Path.Combine(Path.GetTempPath(), $"{Path.GetFileNameWithoutExtension(DecodedFileName)}_rawframe.{Decoder.CodecContext->frame_number}.bmp");
//frame.Save(filename);
BitmapData bmpdata = null;
Texture2D frameTex = null;
try
{
//Create Texture
frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, frame.Width, frame.Height, false, SurfaceFormat.Color); //GC will collect frameTex
//Fill it with the bitmap.
bmpdata = frame.LockBits(new Rectangle(0, 0, frame.Width, frame.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);// System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte[] texBuffer = new byte[bmpdata.Width * bmpdata.Height * 4]; //GC here
Marshal.Copy(bmpdata.Scan0, texBuffer, 0, texBuffer.Length);
frameTex.SetData(texBuffer);
}
finally
{
if (bmpdata != null)
{
frame.UnlockBits(bmpdata);
}
}
return frameTex;
}
}
我可以 post 更多,如果你想要它几乎都在我的叉子上
视频将像在 Windows 中一样播放。可以达到 15 fps 的流畅度。 :)
我最终删除了代码的位图部分。它奏效了!所以之前我会将帧转换为位图,然后它将像素从位图中复制到 Texture2D 中。我仔细观察,意识到我可以跳过位图的那一步。很抱歉我的问题不够清楚。
/// <summary>
/// Converts Frame to Texture
/// </summary>
/// <returns>Texture2D</returns>
public Texture2D FrameToTexture2D()
{
Texture2D frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, Decoder.CodecContext->width, Decoder.CodecContext->height, false, SurfaceFormat.Color);
const int bpp = 4;
byte[] texBuffer = new byte[Decoder.CodecContext->width * Decoder.CodecContext->height * bpp];
fixed (byte* ptr = &texBuffer[0])
{
byte*[] srcData = { ptr, null, null, null };
int[] srcLinesize = { Decoder.CodecContext->width * bpp, 0, 0, 0 };
// convert video frame to the RGB data
ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize);
}
frameTex.SetData(texBuffer);
return frameTex;
}