- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我一直在关注 tutorial关于如何使用ffmpeg和 SDL 制作一个没有音频的简单视频播放器(目前)。在浏览教程时,我意识到它已经过时了,而且它使用的许多函数,包括 ffmpeg 和 SDL,都被弃用了。所以我搜索了一个最新的解决方案并找到了一个 stackoverflow 问题 answer这完成了教程所缺少的内容。
但是,它使用的是低质量的 YUV420。我想实现 YUV444,在研究了一些色度二次采样并查看了 YUV 的不同格式后,我对如何实现它感到困惑。据我了解,YUV420 的质量是 YUV444 的四分之一。 YUV444 意味着每个像素都有自己的色度样本,因此更详细,而 YUV420 意味着像素被分组在一起并具有相同的色度样本,因此不太详细。
根据我的理解,不同格式的 YUV(420, 422, 444) 在排列 y、u 和 v 的方式上有所不同。所有这些都有点让人不知所措,因为我对编解码器的处理不多,转换等。非常感谢任何帮助,如果需要其他信息,请在投票前告诉我。
这是来自 answer 的代码我提到了关于转换为 YUV420 的问题:
texture = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,
pCodecCtx->height
);
if (!texture) {
fprintf(stderr, "SDL: could not create texture - exiting\n");
exit(1);
}
// initialize SWS context for software scaling
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_YUV420P,
SWS_BILINEAR,
NULL,
NULL,
NULL);
// set up YV12 pixel array (12 bits per pixel)
yPlaneSz = pCodecCtx->width * pCodecCtx->height;
uvPlaneSz = pCodecCtx->width * pCodecCtx->height / 4;
yPlane = (Uint8*)malloc(yPlaneSz);
uPlane = (Uint8*)malloc(uvPlaneSz);
vPlane = (Uint8*)malloc(uvPlaneSz);
if (!yPlane || !uPlane || !vPlane) {
fprintf(stderr, "Could not allocate pixel buffers - exiting\n");
exit(1);
}
uvPitch = pCodecCtx->width / 2;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame?
if (frameFinished) {
AVPicture pict;
pict.data[0] = yPlane;
pict.data[1] = uPlane;
pict.data[2] = vPlane;
pict.linesize[0] = pCodecCtx->width;
pict.linesize[1] = uvPitch;
pict.linesize[2] = uvPitch;
// Convert the image into YUV format that SDL uses
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pict.data,
pict.linesize);
SDL_UpdateYUVTexture(
texture,
NULL,
yPlane,
pCodecCtx->width,
uPlane,
uvPitch,
vPlane,
uvPitch
);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
SDL_PollEvent(&event);
switch (event.type) {
case SDL_QUIT:
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(screen);
SDL_Quit();
exit(0);
break;
default:
break;
}
}
// Free the YUV frame
av_frame_free(&pFrame);
free(yPlane);
free(uPlane);
free(vPlane);
// Close the codec
avcodec_close(pCodecCtx);
avcodec_close(pCodecCtxOrig);
// Close the video file
avformat_close_input(&pFormatCtx);
经过更多研究后,我了解到在 YUV420 中,首先存储所有 Y,然后依次存储 U 和 V 字节的组合,如下图所示:
(来源:wikimedia.org)
但是我也了解到 YUV444 是按照 U、Y、V 的顺序存储的,并且像这张图所示的那样重复:
我尝试改变代码中的一些东西:
// I changed SDL_PIXELFORMAT_YV12 to SDL_PIXELFORMAT_UYVY
// as to reflect the order of YUV444
texture = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_UYVY,
SDL_TEXTUREACCESS_STREAMING,
pCodecCtx->width,
pCodecCtx->height
);
if (!texture) {
fprintf(stderr, "SDL: could not create texture - exiting\n");
exit(1);
}
// Changed AV_PIX_FMT_YUV420P to AV_PIX_FMT_YUV444P
// for rather obvious reasons
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_YUV444P,
SWS_BILINEAR,
NULL,
NULL,
NULL);
// There are as many Y, U and V bytes as pixels I just
// made yPlaneSz and uvPlaneSz equal to the number of pixels
yPlaneSz = pCodecCtx->width * pCodecCtx->height;
uvPlaneSz = pCodecCtx->width * pCodecCtx->height;
yPlane = (Uint8*)malloc(yPlaneSz);
uPlane = (Uint8*)malloc(uvPlaneSz);
vPlane = (Uint8*)malloc(uvPlaneSz);
if (!yPlane || !uPlane || !vPlane) {
fprintf(stderr, "Could not allocate pixel buffers - exiting\n");
exit(1);
}
uvPitch = pCodecCtx->width * 2;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Rearranged the order of the planes to reflect UYV order
// then set linesize to the number of Y, U and V bytes
// per row
if (frameFinished) {
AVPicture pict;
pict.data[0] = uPlane;
pict.data[1] = yPlane;
pict.data[2] = vPlane;
pict.linesize[0] = pCodecCtx->width;
pict.linesize[1] = pCodecCtx->width;
pict.linesize[2] = pCodecCtx->width;
// Convert the image into YUV format that SDL uses
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pict.data,
pict.linesize);
SDL_UpdateYUVTexture(
texture,
NULL,
yPlane,
1,
uPlane,
uvPitch,
vPlane,
uvPitch
);
//.................................................
但现在我在调用 SDL_UpdateYUVTexture
时遇到了访问冲突...老实说,我不确定哪里出了问题。我认为这可能与 AVPicture pic
的成员 data
和 linesize
设置不当有关,但我不是肯定的。
最佳答案
在网上搜索可能的答案数小时后,我偶然发现了这个 post其中有人询问 YUV444 对打包或平面模式的支持。我发现的唯一当前格式是打包的 AYUV。
他们得到的答案是所有当前支持的格式列表,其中不包括 AYUV。因此SDL不支持YUV444。
唯一的解决方案是使用支持 AYUV/YUV444 的不同库。
关于c++ - 如何将 ffmpeg 视频帧转换为 YUV444?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49101684/
例如,我有 4*4 图像。我想分别提取 Y、U 和 V 分量。如果图像是 YUV 422 ,YUV 420 和 YUV444 怎么办。我有兴趣了解数组的结构 Y、U 和 V 如何存储在 422,420
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 8年前关闭。 Improve this q
我无法理解两者之间的确切区别。从研究中,更多地讨论这两者是不同的,但似乎有一些人将它们归为“4 2 2”抽样方案。 YUV 422(I 和 J 版本):“具有一个亮度平面 Y 和 2 个色度平面 U、
我有 10 个 yuv 输入,每个 yuv 都是 WxH 的帧(ip0_WxH.yuv,ip1_WxH.yuv,...,ip9_WxH.yuv) 我需要连接所有 10 个以创建一个包含所有 10 个帧
我的目标是将我解码的帧写入文件中。我知道我捕捉得很好,因为它显示在我的 SDL 播放中,并且我随后对其进行编码,没有任何问题。但似乎我无法将框架正确写入文件。这是代码: #define PIXFMT
我用ffmpeg做HDR测试视频,我的做法是写一张图片,把图片转成yuv420p,然后用ffmpeg做HDR测试视频。 但我发现从 mp4 读取的 yuv 数据与原始输入不同.. 我在这里被困了一段时
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 已关闭 9 年前。 要求提供代码的问题必须表现出对所解决问题的最低限度的了解。包括尝试的解决方案、为什么它们
我一直在尝试用 C++ 将 YUYV 原始文件转换为 YUV420 原始文件。格式记录在 YUV Formats Page 中.转换后我的输出文件显示为绿色。我采用了来自 Experts Exchan
我正在尝试通过 python 使用 OpenCV 4.1.0 版将平面 YUV 4:2:0 图像转换为 RGB,并且正在努力了解如何格式化数组以传递给 cvtColor 功能。我将所有 3 个 cha
我正在编写一个医疗应用程序,其中有来自 IP 接口(interface)的数据包。其中对像素骨架解码有以下定义。我可以决定在主框架中选择什么来使用不同的像素算法。但我没有正确理解逻辑。 这三种格式是什
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 1年前关闭。 Improve thi
我得到 YUV 到 RGB 函数 1 和 2(来自堆栈溢出) 但是结果是这样的错误http://163.18.62.32/device.jpg 我不明白这一步有什么问题 我的设备是 Moto Mile
我正在使用opencv来实现对象跟踪。我读到 YUV 图像比 RGB 图像更好用。我的问题是,尽管我花了很多时间阅读笔记,但我还是无法理解 YUV 格式。 Y 是亮度,我认为它是根据 R、G、B 分量
我有高清1920x1080 YUV 格式视频。 我想将它们压缩到 640x480和其他转换为其他格式(mp4/avi..) 我使用了以下命令: ffmpeg -f rawvideo -pix_fmt
我正在使用 FFMPEG 从 MXF 视频中提取图像。我有兴趣使用 YUV(最好是 422)颜色空间提取 tiff 格式的图像。 MXF 视频属于 YUV 颜色空间。因此,为什么我想继续在那个色彩空间
我有一个 YUV 文件,我想以 BMP 文件的形式获取每一帧,该怎么做?我可以使用 FFMPEG 和 MPlayer。 最佳答案 您可以使用以下命令: ffmpeg -s widthxheight -
如何从 YUV 视频文件格式中获取信息?我需要了解有关流的信息(例如编解码器、位深度)。使用 ffplay 我可以播放 yuv 视频,但如何获取有关流的信息? 我尝试使用 ffprobe 但它不起作用
我试图将 C++ 程序中生成的数组中的原始 YUV 帧流式传输到使用 FFPEG 的视频。谁能指出我正确的方向? 最佳答案 要将管道 YUV420 平面帧流式传输到 RTMP,请尝试例如 ffmpeg
我有一个要实时流式传输到屏幕的 YUV 数据流(来自视频文件)。 (基本上,我想写一个实时播放视频的程序。) 因此,我正在寻找一种将 YUV 数据发送到屏幕的便携方式。理想情况下,我希望使用可移植的东
我已经通过用 Nvidia 的着色器语言编写的片段着色器实现了 YUV 到 RGB 的转换。 (Y、U 和 V 存储在单独的纹理中,这些纹理通过我的片段着色器中的多纹理组合而成)。它在 OpenGL
我是一名优秀的程序员,十分优秀!