mirror of
https://github.com/mpv-player/mpv
synced 2025-01-10 00:49:32 +00:00
27e5416c12
I thought I'd probably want something like this, so the hardcoded stuff in repack.c can be removed eventually. Of course this has no purpose at all, and will not have any. (For now, this provides only metadata, and nothing uses it, apart from the "test" that dumps it as text.) This adds full support for AV_PIX_FMT_UYYVYY411 (probably out of spite, because the format is 100% useless). Support for some mpv-only formats is missing, ironically. The code goes through _lengths_ to try to make sense out of the FFmpeg AVPixFmtDescriptor data. Which is even more amazing that the new metadata basically mirrors pixdesc, and just adds to it. Considering code complexity and speed issues (it takes time to crunch through all this shit all the time), and especially the fact that pixdesc is very _incomplete_, it would probably better to have our own table to all formats. But then we'd not scramble every time FFmpeg adds a new format, which would be annoying. On the other hand, by using pixdesc, we get the excitement to see whether this code will work, or break everything in catastrophic ways. The data structure still sucks a lot. Maybe I'll redo it again. The text dump is weirdly differently formatted than the C struct - because I'm not happy with the representation. Maybe I'll redo it all over again. In summary: this commit does nothing.
249 lines
9.1 KiB
C
249 lines
9.1 KiB
C
#include <libavutil/frame.h>
|
|
#include <libavutil/pixdesc.h>
|
|
|
|
#include "tests.h"
|
|
#include "video/fmt-conversion.h"
|
|
#include "video/img_format.h"
|
|
#include "video/mp_image.h"
|
|
#include "video/sws_utils.h"
|
|
|
|
int imgfmts[IMGFMT_AVPIXFMT_END - IMGFMT_AVPIXFMT_START + 100];
|
|
int num_imgfmts;
|
|
|
|
static enum AVPixelFormat pixfmt_unsup[100];
|
|
static int num_pixfmt_unsup;
|
|
static bool imgfmts_initialized;
|
|
|
|
static int cmp_imgfmt_name(const void *a, const void *b)
|
|
{
|
|
char *name_a = mp_imgfmt_to_name(*(int *)a);
|
|
char *name_b = mp_imgfmt_to_name(*(int *)b);
|
|
|
|
return strcmp(name_a, name_b);
|
|
}
|
|
|
|
void init_imgfmts_list(void)
|
|
{
|
|
if (imgfmts_initialized)
|
|
return;
|
|
|
|
const AVPixFmtDescriptor *avd = av_pix_fmt_desc_next(NULL);
|
|
for (; avd; avd = av_pix_fmt_desc_next(avd)) {
|
|
enum AVPixelFormat fmt = av_pix_fmt_desc_get_id(avd);
|
|
int mpfmt = pixfmt2imgfmt(fmt);
|
|
if (!mpfmt) {
|
|
assert(num_pixfmt_unsup < MP_ARRAY_SIZE(pixfmt_unsup));
|
|
pixfmt_unsup[num_pixfmt_unsup++] = fmt;
|
|
}
|
|
}
|
|
|
|
for (int fmt = IMGFMT_START; fmt <= IMGFMT_END; fmt++) {
|
|
struct mp_imgfmt_desc d = mp_imgfmt_get_desc(fmt);
|
|
enum AVPixelFormat pixfmt = imgfmt2pixfmt(fmt);
|
|
if (d.id || pixfmt != AV_PIX_FMT_NONE) {
|
|
assert(num_imgfmts < MP_ARRAY_SIZE(imgfmts)); // enlarge that array
|
|
imgfmts[num_imgfmts++] = fmt;
|
|
}
|
|
}
|
|
|
|
qsort(imgfmts, num_imgfmts, sizeof(imgfmts[0]), cmp_imgfmt_name);
|
|
|
|
imgfmts_initialized = true;
|
|
}
|
|
|
|
static const char *comp_type(enum mp_component_type type)
|
|
{
|
|
switch (type) {
|
|
case MP_COMPONENT_TYPE_UINT: return "uint";
|
|
case MP_COMPONENT_TYPE_FLOAT: return "float";
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
static void run(struct test_ctx *ctx)
|
|
{
|
|
init_imgfmts_list();
|
|
|
|
FILE *f = test_open_out(ctx, "img_formats.txt");
|
|
|
|
for (int z = 0; z < num_imgfmts; z++) {
|
|
int mpfmt = imgfmts[z];
|
|
enum AVPixelFormat pixfmt = imgfmt2pixfmt(mpfmt);
|
|
const AVPixFmtDescriptor *avd = av_pix_fmt_desc_get(pixfmt);
|
|
|
|
fprintf(f, "%s: ", mp_imgfmt_to_name(mpfmt));
|
|
if (mpfmt >= IMGFMT_AVPIXFMT_START && mpfmt < IMGFMT_AVPIXFMT_END)
|
|
fprintf(f, "[GENERIC] ");
|
|
|
|
int fcsp = mp_imgfmt_get_forced_csp(mpfmt);
|
|
if (fcsp)
|
|
fprintf(f, "fcsp=%s ", m_opt_choice_str(mp_csp_names, fcsp));
|
|
fprintf(f, "ctype=%s\n", comp_type(mp_imgfmt_get_component_type(mpfmt)));
|
|
|
|
struct mp_imgfmt_desc d = mp_imgfmt_get_desc(mpfmt);
|
|
if (d.id) {
|
|
fprintf(f, " Basic desc: ");
|
|
#define FLAG(t, c) if (d.flags & (t)) fprintf(f, "[%s]", c);
|
|
FLAG(MP_IMGFLAG_BYTE_ALIGNED, "ba")
|
|
FLAG(MP_IMGFLAG_ALPHA, "a")
|
|
FLAG(MP_IMGFLAG_YUV_P, "yuvp")
|
|
FLAG(MP_IMGFLAG_YUV_NV, "nv")
|
|
FLAG(MP_IMGFLAG_YUV, "yuv")
|
|
FLAG(MP_IMGFLAG_RGB, "rgb")
|
|
FLAG(MP_IMGFLAG_LE, "le")
|
|
FLAG(MP_IMGFLAG_BE, "be")
|
|
FLAG(MP_IMGFLAG_PAL, "pal")
|
|
FLAG(MP_IMGFLAG_HWACCEL, "hw")
|
|
fprintf(f, "\n");
|
|
fprintf(f, " planes=%d, chroma=%d:%d align=%d:%d\n",
|
|
d.num_planes, d.chroma_xs, d.chroma_ys, d.align_x, d.align_y);
|
|
fprintf(f, " {");
|
|
for (int n = 0; n < MP_MAX_PLANES; n++) {
|
|
if (n >= d.num_planes) {
|
|
assert(d.bpp[n] == 0 && d.xs[n] == 0 && d.ys[n] == 0);
|
|
continue;
|
|
}
|
|
fprintf(f, "%d/[%d:%d] ", d.bpp[n], d.xs[n], d.ys[n]);
|
|
}
|
|
fprintf(f, "}\n");
|
|
} else {
|
|
fprintf(f, " [NODESC]\n");
|
|
}
|
|
|
|
struct mp_imgfmt_layout pd;
|
|
mp_imgfmt_get_layout(mpfmt, &pd);
|
|
|
|
for (int n = 0; n < d.num_planes; n++) {
|
|
fprintf(f, " %d: %dbits", n, pd.bits[n]);
|
|
if (pd.extra_w)
|
|
fprintf(f, " w=%d", pd.extra_w + 1);
|
|
if (pd.endian_bytes)
|
|
fprintf(f, " endian_bytes=%d", pd.endian_bytes);
|
|
for (int x = 0; x < MP_NUM_COMPONENTS; x++) {
|
|
struct mp_imgfmt_comp_desc cm = pd.comps[x];
|
|
fprintf(f, " {");
|
|
if (cm.plane == n) {
|
|
if (cm.size) {
|
|
fprintf(f, "%d:%d", cm.offset, cm.size);
|
|
if (cm.pad)
|
|
fprintf(f, "/%d", cm.pad);
|
|
} else {
|
|
assert(cm.offset == 0);
|
|
assert(cm.pad == 0);
|
|
}
|
|
}
|
|
fprintf(f, "}");
|
|
}
|
|
fprintf(f, "\n");
|
|
if (pd.extra_w) {
|
|
fprintf(f, " extra_luma_offsets=[");
|
|
for (int x = 0; x < pd.extra_w; x++)
|
|
fprintf(f, " %d", pd.extra_luma_offsets[x]);
|
|
fprintf(f, "]\n");
|
|
}
|
|
}
|
|
|
|
if (!(d.flags & MP_IMGFLAG_HWACCEL) && pixfmt != AV_PIX_FMT_NONE) {
|
|
AVFrame *fr = av_frame_alloc();
|
|
fr->format = pixfmt;
|
|
fr->width = 128;
|
|
fr->height = 128;
|
|
int err = av_frame_get_buffer(fr, MP_IMAGE_BYTE_ALIGN);
|
|
assert(err >= 0);
|
|
struct mp_image *mpi = mp_image_alloc(mpfmt, fr->width, fr->height);
|
|
if (mpi) {
|
|
// A rather fuzzy test, which might fail even if there's no bug.
|
|
for (int n = 0; n < 4; n++) {
|
|
if (!!mpi->planes[n] != !!fr->data[n]) {
|
|
#ifdef AV_PIX_FMT_FLAG_PSEUDOPAL
|
|
if (n == 1 && (avd->flags & AV_PIX_FMT_FLAG_PSEUDOPAL))
|
|
continue;
|
|
#endif
|
|
fprintf(f, " Warning: p%d: %p %p\n", n,
|
|
mpi->planes[n], fr->data[n]);
|
|
}
|
|
if (mpi->stride[n] != fr->linesize[n]) {
|
|
fprintf(f, " Warning: p%d: %d %d\n", n,
|
|
mpi->stride[n], fr->linesize[n]);
|
|
}
|
|
}
|
|
} else {
|
|
fprintf(f, " [NOALLOC]\n");
|
|
}
|
|
talloc_free(mpi);
|
|
av_frame_free(&fr);
|
|
}
|
|
|
|
struct mp_regular_imgfmt reg;
|
|
if (mp_get_regular_imgfmt(®, mpfmt)) {
|
|
fprintf(f, " Regular: planes=%d compbytes=%d bitpad=%d "
|
|
"chroma=%dx%d ctype=%s\n",
|
|
reg.num_planes, reg.component_size, reg.component_pad,
|
|
1 << reg.chroma_xs, 1 << reg.chroma_ys,
|
|
comp_type(reg.component_type));
|
|
for (int n = 0; n < reg.num_planes; n++) {
|
|
struct mp_regular_imgfmt_plane *plane = ®.planes[n];
|
|
fprintf(f, " %d: {", n);
|
|
for (int i = 0; i < plane->num_components; i++) {
|
|
if (i > 0)
|
|
fprintf(f, ", ");
|
|
fprintf(f, "%d", plane->components[i]);
|
|
}
|
|
fprintf(f, "}\n");
|
|
}
|
|
}
|
|
|
|
// This isn't ours, but changes likely affect us.
|
|
if (avd) {
|
|
fprintf(f, " AVD: name=%s chroma=%d:%d flags=0x%"PRIx64, avd->name,
|
|
avd->log2_chroma_w, avd->log2_chroma_h, avd->flags);
|
|
#define FLAGAV(t, c) if (avd->flags & (t)) \
|
|
{fprintf(f, "%s[%s]", pre, c); pre = ""; }
|
|
char *pre = " ";
|
|
FLAGAV(AV_PIX_FMT_FLAG_BE, "be")
|
|
FLAGAV(AV_PIX_FMT_FLAG_PAL, "pal")
|
|
FLAGAV(AV_PIX_FMT_FLAG_BITSTREAM, "bs")
|
|
FLAGAV(AV_PIX_FMT_FLAG_HWACCEL, "hw")
|
|
FLAGAV(AV_PIX_FMT_FLAG_PLANAR, "planar")
|
|
FLAGAV(AV_PIX_FMT_FLAG_RGB, "rgb")
|
|
FLAGAV(AV_PIX_FMT_FLAG_ALPHA, "alpha")
|
|
FLAGAV(AV_PIX_FMT_FLAG_BAYER, "bayer")
|
|
FLAGAV(AV_PIX_FMT_FLAG_FLOAT, "float")
|
|
fprintf(f, "\n");
|
|
for (int n = 0; n < avd->nb_components; n++) {
|
|
const AVComponentDescriptor *cd = &avd->comp[n];
|
|
fprintf(f, " %d: p=%-2d st=%-2d o=%-2d sh=%-2d d=%d\n",
|
|
n, cd->plane, cd->step, cd->offset, cd->shift, cd->depth);
|
|
}
|
|
for (int n = avd->nb_components; n < 4; n++) {
|
|
const AVComponentDescriptor *cd = &avd->comp[n];
|
|
assert(!cd->plane && !cd->step && !cd->offset && !cd->shift &&
|
|
!cd->depth);
|
|
}
|
|
}
|
|
|
|
const AVPixFmtDescriptor *avd2 = av_pix_fmt_desc_next(NULL);
|
|
for (; avd2; avd2 = av_pix_fmt_desc_next(avd2)) {
|
|
enum AVPixelFormat pixfmt2 = av_pix_fmt_desc_get_id(avd2);
|
|
int mpfmt2 = pixfmt2imgfmt(pixfmt2);
|
|
if (mpfmt2 == mpfmt && pixfmt2 != pixfmt)
|
|
fprintf(f, " Ambiguous alias: %s\n", avd2->name);
|
|
}
|
|
}
|
|
|
|
for (int z = 0; z < num_pixfmt_unsup; z++) {
|
|
const AVPixFmtDescriptor *avd = av_pix_fmt_desc_get(pixfmt_unsup[z]);
|
|
fprintf(f, "Unsupported: %s\n", avd->name);
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
assert_text_files_equal(ctx, "img_formats.txt", "img_formats.txt",
|
|
"This can fail if FFmpeg adds new formats or flags.");
|
|
}
|
|
|
|
const struct unittest test_img_format = {
|
|
.name = "img_format",
|
|
.run = run,
|
|
};
|