Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add yuv4mpeg (Y4M) output #619

Merged
merged 3 commits into from
Mar 2, 2021
Merged

Add yuv4mpeg (Y4M) output #619

merged 3 commits into from
Mar 2, 2021

Conversation

ifb
Copy link
Contributor

@ifb ifb commented Feb 18, 2021

ld-chroma-decoder: add 'y4m' to the available --output-format options.

'y4m' output is identical to 'yuv' except with the addition of headers. This
avoids having to specify the dimensions, frame rate, field order, aspect ratio,
and pixel format to downstream consumers such as ffmpeg.

For example:
ld-chroma-decoder -p y4m input - | ffmpeg -f yuv4mpegpipe -i - output.mkv

@Gamnn
Copy link
Contributor

Gamnn commented Feb 18, 2021

Getting an Operation not permitted error when putting it into ffmpeg (4.2.4-1ubuntu0.1)
It also fails in mpv 0.32.0 which uses ffmpeg libraries.

Header is:

YUV4MPEG2 W760 H488 F30000:1001 It A1952:2280 C444p16 XYSCSS=444P16 XCOLORRANGE=LIMITED
FRAME

I compared it to vspipe's y4m header, which does work:

YUV4MPEG2 C444p16 W760 H488 F30000:1001 Ip A0:0 XLENGTH=53563
FRAME

After removing XCOLORRANGE=LIMITED from the header, both ffmpeg and mpv are happy.

ffmpeg -debug -f yuv4mpegpipe -i test.y4m test.mkv
ffmpeg version 4.2.4-1ubuntu0.1 Copyright (c) 2000-2020 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.3.0-10ubuntu2)
  configuration: --prefix=/usr --extra-version=1ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
 matched as AVOption 'debug' with argument '-f'.
Reading option 'yuv4mpegpipe' ... matched as output url.
Reading option '-i' ... matched as input url with argument 'test.y4m'.
Reading option 'test.mkv' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Successfully parsed a group of options.
Parsing a group of options: input url test.y4m.
Successfully parsed a group of options.
Opening an input file: test.y4m.
[NULL @ 0x55948d669880] Opening 'test.y4m' for reading
[file @ 0x55948d66a280] Setting default whitelist 'file,crypto'
[yuv4mpegpipe @ 0x55948d669880] Format yuv4mpegpipe probed with size=2048 and score=100
[AVIOContext @ 0x55948d672640] Statistics: 32768 bytes read, 0 seeks
test.y4m: Operation not permitted

mpv -v test.y4m
[cplayer] Command line options: '-v' 'test.y4m'
[cplayer] mpv 0.32.0 Copyright © 2000-2020 mpv/MPlayer/mplayer2 projects
[cplayer]  built on UNKNOWN
[cplayer] ffmpeg library versions:
[cplayer]    libavutil       56.31.100
[cplayer]    libavcodec      58.54.100
[cplayer]    libavformat     58.29.100
[cplayer]    libswscale      5.5.100
[cplayer]    libavfilter     7.57.100
[cplayer]    libswresample   3.5.100
[cplayer] ffmpeg version: 4.2.4-1ubuntu0.1
[cplayer] 
[cplayer] Configuration: ./waf configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --confdir=/etc/mpv --zshdir=/usr/share/zsh/vendor-completions --enable-cdda --enable-dvdnav --enable-libmpv-shared --enable-libsmbclient --enable-sdl2 --enable-sndio --disable-build-date --enable-dvbin
[cplayer] List of enabled features: 52arch aligned_alloc alsa asm atomics caca cdda cplayer cplugins debug-build drm drmprime dvbin dvdnav egl egl-drm egl-helpers egl-x11 fchmod ffmpeg gbm gbm.h gl gl-wayland gl-x11 glibc-thread-name glob glob-posix gnuc gpl iconv jack jpeg lcms2 libarchive libass libass-osd libav-any libavcodec libavdevice libavutil libbluray libdl libm libmpv-shared librt libsmbclient linux-fstatfs lua memfd_create optimize oss-audio plain-gl posix posix-or-mingw posix-spawn posix-spawn-native pthreads pulse rubberband sdl2 sdl2-audio sdl2-gamepad sdl2-video sndio stdatomic uchardet vaapi vaapi-drm vaapi-egl vaapi-wayland vaapi-x-egl vaapi-x11 vdpau vdpau-gl-x11 vt.h wayland wayland-protocols x11 xv zlib
[cplayer] Reading config file /etc/mpv/encoding-profiles.conf
[cplayer] Applying profile 'default'...
[cplayer] Reading config file /etc/mpv/mpv.conf
[cplayer] Applying profile 'default'...
[cplayer] Setting option 'hwdec' = 'vaapi' (flags = 4)
[cplayer] Reading config file /home/gamn/.config/mpv/mpv.conf
[cplayer] Applying profile 'default'...
[cplayer] Setting option 'hwdec' = 'vaapi-copy' (flags = 4)
[cplayer] Setting option 'screenshot-format' = 'png' (flags = 4)
[cplayer] Setting option 'v' = '' (flags = 8)
[cplayer] Waiting for scripts...
[cplayer] Set property: shared-script-properties -> 1
[cplayer] Set property: shared-script-properties -> 1
[cplayer] Set property: shared-script-properties -> 1
[osd/libass] Shaper: FriBidi 0.19.7 (SIMPLE) HarfBuzz-ng 2.6.4 (COMPLEX)
[osd/libass] Setting up fonts...
[osd/libass] Using font provider fontconfig
[osd/libass] Done.
[cplayer] Done loading scripts.
[cplayer] Running hook: ytdl_hook/on_load
[ytdl_hook] ytdl:// hook 
[ytdl_hook] not a ytdl:// url 
[osd/libass] Shaper: FriBidi 0.19.7 (SIMPLE) HarfBuzz-ng 2.6.4 (COMPLEX)
[ifo_dvdnav] Opening test.y4m
[osd/libass] Setting up fonts...
[bdmv/bluray] Opening test.y4m
[file] Opening test.y4m
[demux] Trying demuxers for level=normal.
[lavf] Found 'yuv4mpegpipe' at score=100 size=2048.
[lavf] avformat_open_input() failed
[demux] Trying demuxers for level=unsafe.
[osd/libass] Using font provider fontconfig
[osd/libass] Done.
[lavf] Found 'yuv4mpegpipe' at score=100 size=2048.
[lavf] avformat_open_input() failed
[cplayer] Opening failed or was aborted: test.y4m
[cplayer] Running hook: ytdl_hook/on_load_fail
[ytdl_hook] full hook 
[cplayer] finished playback, unrecognized file format (reason 4)
[cplayer] Failed to recognize file format.
[cplayer] 
[cplayer] 
[cplayer] Exiting... (Errors when loading file)
[cplayer] Set property: shared-script-properties -> 1

@atsampson
Copy link
Collaborator

It might be this change, which increased the max header size in yuv4mpegdec from 80 bytes to 96 in ffmpeg 4.3 - the header quoted above is > 80 bytes long...

@ifb
Copy link
Contributor Author

ifb commented Feb 18, 2021

Yep. The current patch works as-is with ffmpeg master. ffmpeg 4.2.4 shipped in Ubuntu 20.04 doesn't like the long header. Removing XCOLORRANGE does not affect ffmpeg master, so we can simply remove XCOLORRANGE to shorten the Y4M header.
Old ffmpeg users just won't get to simplify their command lines as much.

Note that removing XCOLORRANGE causes 4.2.4 to ignore the field order too, so you get progressive output on top of no explicit range signaling in the container. Not the end of the world and it maintains the status quo with 4.2.4 ,but users may want to upgrade ffmpeg for things to work a little more intelligently.

Also the Ubuntu build of 4.2.4 doesn't seem to support monochrome (X264_CSP_I400) in its libx264 wrapper. It's present in libx264.c behind a #define, so maybe there's some magic to enabling it. You would think setting -pix_fmt gray would be enough (it is with static builds from here).

@Gamnn
Copy link
Contributor

Gamnn commented Feb 18, 2021

Ah-hah. Perhaps it would be better to leave it in, and remove the aspect ratio from the header instead. That also seems make it short enough to work with the stock ffmpeg, and is easy to specify manually.

@ifb
Copy link
Contributor Author

ifb commented Feb 18, 2021

The libx264 in Ubuntu 20.04 is too old to support monochrome, so that explains that.

The "X" options are technically comments, so I'm inclined to drop something like XCOLORSPACE over a "core" field like aspect ratio. However, I understand adding -aspect 4:3 is a little easier, given how brain-damaged the packaged ffmpeg is. 🤷

Just throw a new ffmpeg binary in /opt/bin and you can stop caring. 😄

return config.outputY4m;
}

QString MonoDecoder::getHeaders() const
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can getHeaders be in the Decoder base class, rather than being replicated three times? The code looks the same in all three versions...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started out doing that, but the base class doesn't have a Configuration struct. I gave it a private Decoder::Configuration config, but my C++ skillz are lacking and Decoder::getHeaders() returns nonsense, despite me setting config.xxxx in the derived classes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yes - the base class can't have a Configuration member because it needs to be one of the subclasses. Leave it as is for now then and I'll have a think...

@Gamnn
Copy link
Contributor

Gamnn commented Feb 18, 2021

The "X" options are technically comments, so I'm inclined to drop something like XCOLORSPACE over a "core" field like aspect ratio. However, I understand adding -aspect 4:3 is a little easier, given how brain-damaged the packaged ffmpeg is.

Well, my thought being is there are non-4:3 aspect LDs as well, and it's not a vital parameter for y4m. Whichever you think is better for compatibility though.

@ifb
Copy link
Contributor Author

ifb commented Feb 18, 2021

Good point about anamorphic content. Setting aspect ratio to unknown seems reasonable. Alternatively, could add an anamorphic flag to ld-chroma-decode?

Oh, and I didn't try to reduce the fraction. That would save some header space, but maybe not enough to matter?

@atsampson
Copy link
Collaborator

We could have a field in the .tbc.json for aspect ratio, and assume 4:3 otherwise - the VBI decoder could pick it up from WSS automatically. (It's also another thing that padding makes tricky, because the output isn't actually 4:3 until you crop off the padding...)

@Gamnn
Copy link
Contributor

Gamnn commented Feb 18, 2021

Yeah. I tried YUV4MPEG2 W760 H488 F30000:1001 It A4:3 C444p16 XYSCSS=444P16 XCOLORRANGE=LIMITED but it seems to be just 1 character too long.

It's a shame they didn't choose a shorter parameter name than colorrange given the header size constraints.

But since we're supporting Ubuntu 20.04 LTS, it's probably best to keep it under 80 for the time being. So gotta cut one or the other. Though, what does XYSCSS do? Why is it needed in addition to the C444p16?

@ifb
Copy link
Contributor Author

ifb commented Feb 18, 2021

Separate from this patch, I'd argue for mod2 instead of mod8 padding, in part because it borks the aspect ratio.

But that's a separate discussion for later.

@ifb
Copy link
Contributor Author

ifb commented Feb 18, 2021

Yeah. I tried YUV4MPEG2 W760 H488 F30000:1001 It A4:3 C444p16 XYSCSS=444P16 XCOLORRANGE=LIMITED but it seems to be just 1 character too long.

It's a shame they didn't choose a shorter parameter name than colorrange given the header size constraints.

But since we're supporting Ubuntu 20.04 LTS, it's probably best to keep it under 80 for the time being. So gotta cut one or the other. Though, what does XYSCSS do? Why is it needed in addition to the C444p16?

It's a limitation of ffmpeg's parser that has been fixed. There's nothing in the format that limits the header size. It's an implementation detail in 2.4.3.

Also 'A4:3' isn't correct. That field is for the PAR, not DAR.

XYSCSS is because the original mjpegtools implementation of Y4M only had a few formats supported. Everything else is a semi-standard extension.

https://git.ffmpeg.org/gitweb/ffmpeg.git/blob_plain/HEAD:/libavformat/yuv4mpegenc.c
https://wiki.multimedia.cx/index.php/YUV4MPEG2

@Gamnn
Copy link
Contributor

Gamnn commented Feb 18, 2021

It's a limitation of ffmpeg's parser that has been fixed. There's nothing in the format that limits the header size. It's an implementation detail in 2.4.3.

Well, even if not inherent in the format, ffmpeg's implementation is still limited to 96 bytes in master. Otherwise it might have been nice to also include the XLENGTH parameter like vspipe does.

@ifb
Copy link
Contributor Author

ifb commented Feb 19, 2021

Updated pull request. Added a field to the .json for signaling widescreen, which is always false for now.

The Y4M pixel aspect ratios are calculated before mod8 padding. This makes the DAR correct no matter what padding there may be, even if it isn't exactly 4:3.

Also, @Gamnn was correct to ask about the XYSCSS field. Dropping it gives us enough room in the header for even the packaged ffmpeg to "work". YMMV. Respect for auto-setting full/limited range and field order seems to be output codec dependent. Interlacing is set automatically in ffv1, but not libx264.

XLENGTH has been added.

@ifb ifb force-pushed the add-y4m branch 4 times, most recently from 9b00015 to d7e8ac5 Compare February 19, 2021 05:38
@ifb
Copy link
Contributor Author

ifb commented Feb 19, 2021

I spoke too soon. With ffmpeg 4.2.4, adding XLENGTH works for PAL content if it is under 10,000 frames but NTSC is broken no matter what.

@Gamnn What actually uses XLENGTH? vspipe writes it, but if x264 and ffmpeg don't use it, what does?

@Gamnn
Copy link
Contributor

Gamnn commented Feb 19, 2021

I spoke too soon. With ffmpeg 4.2.4, adding XLENGTH works for PAL content if it is under 10,000 frames but NTSC is broken no matter what.

I was worried CLV discs might push it over the limit.

@Gamnn What actually uses XLENGTH? vspipe writes it, but if x264 and ffmpeg don't use it, what does?

🤷 Nothing I currently use currently does, so it was just a "might be nice." I'd care more about it if ffmpeg did use it- always nice to see an ETA.

@oyvindln
Copy link
Contributor

If there are some variations of options that don't work with older ffmpeg, one option is to have an extra option that adds the additional settings that are convenient but won't work with all version.

@ifb
Copy link
Contributor Author

ifb commented Feb 19, 2021

If there are some variations of options that don't work with older ffmpeg, one option is to have an extra option that adds the additional settings that are convenient but won't work with all version.

We can fit everything that matters. XYSCSS is for legacy compatibility before the additions to XCOLORSPACE were "standardized." XLENGTH is written by vspipe, but doesn't seem to be read by anything. If we drop both, we can easily fit within the stock ffmpeg's 80-byte header limit.

Using ffmpeg master gets you more automatic settings for field order and limited/full range, but even master is not consistent with different codecs (ffv1 will automatically encode interlaced, libx264 will not). Oh, well. Dimensions, frame rate, and colorspace are the big ones and those work fine now.

@Gamnn
Copy link
Contributor

Gamnn commented Feb 21, 2021

I noticed that while -f mono does set it to Cmono16, using --blackandwhite with another decoder doesn't. Other than that, it's looking good.

@ifb
Copy link
Contributor Author

ifb commented Feb 21, 2021

I noticed that while -f mono does set it to Cmono16, using --blackandwhite with another decoder doesn't. Other than that, it's looking good.

That's expected behavior, the same as --output-format yuv. I considered doing as you suggest, but aside from the slightly added complexity, I thought it might be a little confusing if the decoder pixel format changed based on other flags. For now, only mono outputs grayscale, but I don't have a strong opinion about it. Of course, confusion is less of an issue if you're using y4m and all of this gets signaled automatically.

--blackandwhite is an alias for --chroma-gain 0. Other than debugging, is either more useful than -f mono?

Couldn't --blackandwhite just as easily be an alias for -f mono?

@Gamnn
Copy link
Contributor

Gamnn commented Feb 24, 2021

--blackandwhite is an alias for --chroma-gain 0. Other than debugging, is either more useful than -f mono?

Couldn't --blackandwhite just as easily be an alias for -f mono?

-f mono goes through no y/c separation, so it will leave chroma dots in the output if there's any color information in the source. But it's ideal for sources that have no color information as it will be free of any defects caused by chroma decoders.
Using --blackandwhite or --chroma-gain 0 with another decoder goes through the separation, then discards the chroma, leaving the output free of chroma dots. A use case for this might be a black & white film with a color cast.
It's not a huge deal, but since it's only luma at this point it would make sense to also output it at gray16.

@ifb
Copy link
Contributor Author

ifb commented Feb 24, 2021

Patchset updated.

--blackandwhite outputs GRAY16 now.

@ifb ifb force-pushed the add-y4m branch 2 times, most recently from afab756 to 20a0773 Compare February 25, 2021 18:01
ifb added 3 commits March 1, 2021 19:06
We assume 4:3 for now, but later the VBI decoder could set it automatically.
ld-chroma-decoder: add 'y4m' to the available --output-format options.

'y4m' output is identical to 'yuv' except with the addition of headers. This
avoids having to specify the dimensions, frame rate, aspect ratio, and pixel
format to downstream consumers such as ffmpeg.

For example:
ld-chroma-decoder -p y4m input - | ffmpeg -f yuv4mpegpipe -i - output.mkv
Previously, only the mono decoder used GRAY16.
@ifb
Copy link
Contributor Author

ifb commented Mar 2, 2021

Rebased. Anything left I need to address?

Copy link
Collaborator

@atsampson atsampson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@atsampson atsampson merged commit 96d4b47 into happycube:master Mar 2, 2021
@ifb ifb deleted the add-y4m branch January 21, 2023 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants