Commit 485da039 authored by Guillaume Roguez's avatar Guillaume Roguez

video: fix VideoFrame::yuv422_clear_to_black()

This method wasn't able to treat some non-planar YUV pixel formats,
like YUYV422, giving a green background.
This patchset fixes that by giving a true black background when format
is non-planar YUV.

Note: this method continue to not working for non-YUV format,
as before, but it's not checked.

Issue: #81116
Change-Id: I55ec947d1474fc55dee861510623b8e91ef7f467
parent 58863eca
......@@ -136,4 +136,18 @@ void ring_url_split(const char *url,
path, path_size, url);
}
bool
is_yuv_planar(const AVPixFmtDescriptor& desc)
{
if (not (desc.flags & AV_PIX_FMT_FLAG_PLANAR) or desc.flags & AV_PIX_FMT_FLAG_RGB)
return false;
/* handle formats that do not use all planes */
unsigned used_bit_mask = (1u << desc.nb_components) - 1;
for (unsigned i = 0; i < desc.nb_components; ++i)
used_bit_mask &= ~(1u << desc.comp[i].plane);
return not used_bit_mask;
}
}} // namespace ring::libav_utils
......@@ -18,13 +18,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __LIBAV_UTILS_H__
#define __LIBAV_UTILS_H__
#pragma once
#include <vector>
#include <map>
#include <string>
struct AVPixFmtDescriptor;
namespace ring { namespace libav_utils {
void ring_avcodec_init();
......@@ -39,6 +40,6 @@ namespace ring { namespace libav_utils {
char *hostname, size_t hostname_size, int *port,
char *path, size_t path_size);
}} // namespace ring::libav_utils
bool is_yuv_planar(const AVPixFmtDescriptor& desc);
#endif // __LIBAV_UTILS_H__
}} // namespace ring::libav_utils
......@@ -19,11 +19,13 @@
*/
#include "libav_deps.h" // MUST BE INCLUDED FIRST
#include "libav_utils.h"
#include "media_buffer.h"
#include "dring/videomanager_interface.h"
#include <new>
#include <new> // std::bad_alloc
#include <cstdlib>
#include <cstring> // std::memset
namespace ring {
......@@ -151,12 +153,61 @@ videoFrameSize(int format, int width, int height)
void
yuv422_clear_to_black(VideoFrame& frame)
{
auto libav_frame = frame.pointer();
const auto libav_frame = frame.pointer();
const auto desc = av_pix_fmt_desc_get((AVPixelFormat)libav_frame->format);
if (not desc)
return;
memset(libav_frame->data[0], 0, libav_frame->linesize[0] * libav_frame->height);
// 128 is the black level for U/V channels
memset(libav_frame->data[1], 128, libav_frame->linesize[1] * libav_frame->height / 2);
memset(libav_frame->data[2], 128, libav_frame->linesize[2] * libav_frame->height / 2);
if (not libav_utils::is_yuv_planar(*desc)) {
// not planar
auto stride = libav_frame->linesize[0];
if (libav_frame->width % 2) {
// non-even width (16bits write x-loop)
for (int y = 0; y < libav_frame->height; ++y) {
auto src = &libav_frame->data[0][y * stride];
for (int x = 0; x < libav_frame->width; ++x) {
#if __BYTE_ORDER == __LITTLE_ENDIAN
*((uint16_t*)src) = 0x8000;
#else
*((uint16_t*)src) = 0x0080;
#endif
src += 2;
}
}
} else if (libav_frame->width % 4) {
// non-quad width (32bits write x-loop)
for (int y = 0; y < libav_frame->height; ++y) {
auto src = &libav_frame->data[0][y * stride];
for (int x = 0; x < libav_frame->width / 2; ++x) {
#if __BYTE_ORDER == __LITTLE_ENDIAN
*((uint32_t*)src) = 0x80008000;
#else
*((uint32_t*)src) = 0x00800080;
#endif
src += 4;
}
}
} else {
// quad width (64bits write x-loop)
for (int y = 0; y < libav_frame->height; ++y) {
auto src = &libav_frame->data[0][y * stride];
for (int x = 0; x < libav_frame->width / 4; ++x) {
#if __BYTE_ORDER == __LITTLE_ENDIAN
*((uint64_t*)src) = 0x8000800080008000;
#else
*((uint64_t*)src) = 0x0080008000800080;
#endif
src += 8;
}
}
}
} else {
// planar
std::memset(libav_frame->data[0], 0, libav_frame->linesize[0] * libav_frame->height);
// 128 is the black level for U/V channels
std::memset(libav_frame->data[1], 128, libav_frame->linesize[1] * (libav_frame->height >> desc->log2_chroma_w));
std::memset(libav_frame->data[2], 128, libav_frame->linesize[2] * (libav_frame->height >> desc->log2_chroma_h));
}
}
#endif // RING_VIDEO
......
......@@ -19,6 +19,7 @@
*/
#include "libav_deps.h" // MUST BE INCLUDED FIRST
#include "libav_utils.h"
#include "video_scaler.h"
#include "media_buffer.h"
#include "logger.h"
......@@ -69,21 +70,6 @@ VideoScaler::scale_with_aspect(const VideoFrame& input, VideoFrame& output)
output_frame->height, true);
}
static inline bool is_yuv_planar(const AVPixFmtDescriptor *desc)
{
unsigned used_bit_mask = (1u << desc->nb_components) - 1;
if (not (desc->flags & AV_PIX_FMT_FLAG_PLANAR)
or desc->flags & AV_PIX_FMT_FLAG_RGB)
return false;
/* handle formats that do not use all planes */
for (unsigned i = 0; i < desc->nb_components; ++i)
used_bit_mask &= ~(1u << desc->comp[i].plane);
return not used_bit_mask;
}
void
VideoScaler::scale_and_pad(const VideoFrame& input, VideoFrame& output,
unsigned xoff, unsigned yoff,
......@@ -130,8 +116,8 @@ VideoScaler::scale_and_pad(const VideoFrame& input, VideoFrame& output,
}
// Make an offset'ed copy of output data from xoff and yoff
const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get((AVPixelFormat)output_frame->format);
if (is_yuv_planar(out_desc)) {
const auto out_desc = av_pix_fmt_desc_get((AVPixelFormat)output_frame->format);
if (libav_utils::is_yuv_planar(*out_desc)) {
unsigned x_shift = out_desc->log2_chroma_w;
unsigned y_shift = out_desc->log2_chroma_h;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment