Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#9636 closed defect (invalid)

Unable to remux HEVC stream from MKV to MKV

Reported by: mysterious Owned by:
Priority: normal Component: undetermined
Version: git-master Keywords:
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:

With some MKV source files, copying the HEVC video stream to an MKV output may produce the error:

Could not write header for output file #0 (incorrect codec parameters ?): Invalid data found when processing input
Error initializing output stream 0:0 --

How to reproduce:

Run the following command with the attached sample.mkv:

ffmpeg -i sample.mkv -vcodec copy output.mkv

Tried on v4.4.1, but reproduced on Git Windows build 2022-02-07-git-04cc7a5548-essentials_build-www.gyan.dev

Full output:

ffmpeg version 2022-02-07-git-04cc7a5548-essentials_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 11.2.0 (Rev7, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
  libavutil      57. 21.100 / 57. 21.100
  libavcodec     59. 20.100 / 59. 20.100
  libavformat    59. 17.101 / 59. 17.101
  libavdevice    59.  5.100 / 59.  5.100
  libavfilter     8. 26.101 /  8. 26.101
  libswscale      6.  5.100 /  6.  5.100
  libswresample   4.  4.100 /  4.  4.100
  libpostproc    56.  4.100 / 56.  4.100
Input #0, matroska,webm, from 'b.mkv':
  Metadata:
    encoder         : libebml v1.3.7 + libmatroska v1.5.0
    creation_time   : 2022-02-10T10:46:36.000000Z
  Duration: 00:00:04.51, start: 0.000000, bitrate: 723 kb/s
  Stream #0:0: Video: hevc (Main), yuv420p(tv, bt709), 1920x1080, SAR 1:1 DAR 16:9, 23.98 fps, 23.98 tbr, 1k tbn (default)
    Metadata:
      title           : Presented By EMBER
      BPS-eng         : 707780
      DURATION-eng    : 00:00:04.505000000
      NUMBER_OF_FRAMES-eng: 108
      NUMBER_OF_BYTES-eng: 398569
      _STATISTICS_WRITING_APP-eng: mkvmerge v34.0.0 ('Sight and Seen') 64-bit
      _STATISTICS_WRITING_DATE_UTC-eng: 2022-02-10 10:46:36
      _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
File 'c.mkv' already exists. Overwrite? [y/N] y
Could not write header for output file #0 (incorrect codec parameters ?): Invalid data found when processing input
Error initializing output stream 0:0 --
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
    Last message repeated 1 times

Output from ffprobe -show_format -show_streams -print_format json sample.mkv

{
    "streams": [
        {
            "index": 0,
            "codec_name": "hevc",
            "codec_long_name": "H.265 / HEVC (High Efficiency Video Coding)",
            "profile": "Main",
            "codec_type": "video",
            "codec_tag_string": "[0][0][0][0]",
            "codec_tag": "0x0000",
            "width": 1920,
            "height": 1080,
            "coded_width": 1920,
            "coded_height": 1080,
            "closed_captions": 0,
            "film_grain": 0,
            "has_b_frames": 2,
            "sample_aspect_ratio": "1:1",
            "display_aspect_ratio": "16:9",
            "pix_fmt": "yuv420p",
            "level": 123,
            "color_range": "tv",
            "color_space": "bt709",
            "color_transfer": "bt709",
            "color_primaries": "bt709",
            "chroma_location": "left",
            "refs": 1,
            "r_frame_rate": "27021/1127",
            "avg_frame_rate": "27021/1127",
            "time_base": "1/1000",
            "start_pts": 0,
            "start_time": "0.000000",
            "extradata_size": 1975,
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0,
                "captions": 0,
                "descriptions": 0,
                "metadata": 0,
                "dependent": 0,
                "still_image": 0
            },
            "tags": {
                "title": "Presented By EMBER",
                "BPS-eng": "707780",
                "DURATION-eng": "00:00:04.505000000",
                "NUMBER_OF_FRAMES-eng": "108",
                "NUMBER_OF_BYTES-eng": "398569",
                "_STATISTICS_WRITING_APP-eng": "mkvmerge v34.0.0 ('Sight and Seen') 64-bit",
                "_STATISTICS_WRITING_DATE_UTC-eng": "2022-02-10 10:46:36",
                "_STATISTICS_TAGS-eng": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
            }
        }
    ],
    "format": {
        "filename": "sample.mkv",
        "nb_streams": 1,
        "nb_programs": 0,
        "format_name": "matroska,webm",
        "format_long_name": "Matroska / WebM",
        "start_time": "0.000000",
        "duration": "4.505000",
        "size": "407168",
        "bit_rate": "723050",
        "probe_score": 100,
        "tags": {
            "encoder": "libebml v1.3.7 + libmatroska v1.5.0",
            "creation_time": "2022-02-10T10:46:36.000000Z"
        }
    }
}

Attachments (1)

sample.mkv (397.6 KB ) - added by mysterious 2 years ago.

Download all attachments as: .zip

Change History (11)

by mysterious, 2 years ago

Attachment: sample.mkv added

comment:1 by mkver, 2 years ago

Resolution: invalid
Status: newclosed

The extradata (CodecPrivate in Matroska parlance) of HEVC in Matroska is supposed to contain a HEVCDecoderConfigurationRecord and there is currently only one legal version of HEVCDecoderConfigurationRecord, namely version 1. Yet your file claims to be of version 0 (as the first byte of the CodecPrivate indicates). Simply remuxing this would lead to an invalid file (because version 0 is not valid).
If one changes the byte 0x00 at offset 4329 in your file by 0x01, remuxing succeeds (and the file seems fine).

comment:2 by mysterious, 2 years ago

Thanks for the suggestion and quick response!

Is there some option/way to force ffmpeg to ignore such bad configurations and either generate an illegal file, or apply your suggested patch to make it legal?
I'm running this from a script with unknown inputs, so manually patching files isn't really feasible. ffmpeg already accepts it as input, and other tools (like mkvmerge) seem to handle it fine (I'm guessing they aren't as strict) so it would be nice if ffmpeg's strictness could be tuned to a similar level, despite the undesirable output it'd generate.

It seems like the '-err_detect' option only applies to input handling, not muxing, as setting it to 'ignore_err' still outputs an error. I couldn't find an option

comment:3 by mkver, 2 years ago

There is no such option (and I don't think we should add an option to allow the creation of spec-incompliant files). And automatically fixing these files would mean that one would have to be sure that the version is the only thing that is wrong.

There is btw a workaround: Use the hevc_mp4toannexb bitstream filter.

Last edited 2 years ago by mkver (previous) (diff)

comment:4 by mysterious, 2 years ago

Appreciate the response and suggestion!

And automatically fixing these files would mean that one would have to be sure that the version is the only thing that is wrong.

From what I can tell, the demuxer/decoder have no issues with the file (and doesn't even output a warning, from my test), which would suggest that nothing else (significant) is wrong. In other words, ffmpeg already is automatically fixing the stream, whether explicitly or implicitly (by ignoring the version).

It would seem logical to me that the muxer should apply this same fix (or otherwise operate in the same way as the demuxer) to be consistent with everything else, or have the demuxer reject the file entirely. The mismatch between demuxer and muxer here can be surprising to a user, and feels odd.

I'd imagine that if an input file is bad, the demuxer/decoder should be the gatekeeper here, instead of the muxer.

in reply to:  4 comment:5 by mkver, 2 years ago

Replying to mysterious:

Appreciate the response and suggestion!

And automatically fixing these files would mean that one would have to be sure that the version is the only thing that is wrong.

From what I can tell, the demuxer/decoder have no issues with the file (and doesn't even output a warning, from my test), which would suggest that nothing else (significant) is wrong. In other words, ffmpeg already is automatically fixing the stream, whether explicitly or implicitly (by ignoring the version).

It would seem logical to me that the muxer should apply this same fix (or otherwise operate in the same way as the demuxer) to be consistent with everything else, or have the demuxer reject the file entirely. The mismatch between demuxer and muxer here can be surprising to a user, and feels odd.

I'd imagine that if an input file is bad, the demuxer/decoder should be the gatekeeper here, instead of the muxer.

This is completely wrong: The demuxer/decoder should handle everything they encounter as well as possible; but muxers should not output invalid files (this is called Postel's law). If we made the decoder more strict and error out on potentially playable, but out-of-spec content, the user will receive/see worse output; but if we allow to create out-of-spec files, these files will be more widespread.

comment:6 by mysterious, 2 years ago

I get where you're coming from, though one could also say that these files exist because decoders accept them. Trying to accept everything leads to cases such as the infamous crazy HTML color parsing rules https://stackoverflow.com/questions/8318911 becoming standard, due to early browsers liberally accepting anything (forcing later browsers to adopt the same rules).

Of course, you could argue the issue either way, and I'm not here to debate which principle is better, just that one should keep in mind that ideals aren't universally the best approach.

I'm actually not suggesting that invalid files have to be generated, just that it makes sense for the fix ffmpeg already does be applied to its output.
In fact, ffmpeg already does this most of the time (where the stream isn't being copied), I'm just suggesting it should be applied in the one case where it doesn't.

As you suggest, not fixing a broken input means the user would receive worse output, and I don't see why users using the MKV muxer should be excluded here.
I don't mind if this "fixing functionality" is held behind a user-supplied flag. I know the 'hevc_mp4toannexb' filter works here, but it requires being more selective (have to check if input is HEVC), and may not apply to other scenarios with different codecs that could crop up.

Thanks again for the response!

comment:7 by mkver, 2 years ago

The decoder does not "fix" anything; the decoder merely does not check the version. This makes sense for a decoder: After all, it has to be prepared for garbage in the non-version fields anyway.

comment:8 by mysterious, 2 years ago

the decoder merely does not check the version

In other words, the decoder assumes the version is 1.
There may not be any specific code to set the version to 1, but it behaves exactly as if it had.

This is what I meant by an implicit fix - it fixes the problem by ignoring it. Whether there's specifically code to fix anything is irrelevant in the grand scheme, as it behaves as if a fix was put in place.

Even if you disagree with the above, I think a 'make it work as best as you can' style switch can be useful for a number of scenarios.

Anyway, it seems clear to me that there's no interest in addressing this issue, so I see no reason to continue this debate. Although I disagree, I understand and respect your position, and appreciate the time you've taken to advise and respond. :)

comment:9 by mkver, 2 years ago

You still don't seem to understand the issue: Just ignoring the version still creates invalid output files with a muxer.

comment:10 by mysterious, 2 years ago

As I doubt there'll be any change regarding ffmpeg on this front, for future people who find this and are having the same issue, I've written a patch to address it.

If the HEVC stream would be rejected, and the version is 0, the patch will spit out a warning and change it to a 1. I've limited this to version=0, as opposed to any version (I presume that some tools output this specifically) as there seems to be some magic number detection in the code, so limiting the scope to reduce potentially unwanted side effects.

Note: See TracTickets for help on using tickets.