3
votes

I have 1000+ videos with wrong Level information, and hence do not play on some devices. They are H.264 baseline with aac audio in mp4 container. I want to correct them but avoid re-encoding. Am I right in assuming that this is possible and will be faster? How do I identify the level_idc bits in the streams? Will all streams have them in the same location? I expect this to be in just one place in the stream, is this assumption correct? Update: I came across a windows executable link that claims to do this. I want to be able to do this commandline on unix, so I can script it.

More Updates: As per Roman's answer below. I dug up MP4 syntax and found that Profile and Level information are part of avcC atom under stsd. I could see that level was set to 1E, I corrected it to 1F. Before: 61 76 63 43 01 42 C0 1E FF E1 00 19 67 42 C0 1E D9 After: 61 76 63 43 01 42 C0 1F FF E1 00 19 67 42 C0 1E D9 with that the MediaInfo changed to:

Video
ID                                       : 1
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : [email protected]
Format settings, CABAC                   : No
Format settings, ReFrames                : 3 frames
Muxing mode                              : Container [email protected]
Codec ID                                 : avc1
Codec ID/Info                            : Advanced Video Coding
Duration                                 : 1mn 4s
Bit rate                                 : 3 000 Kbps
Width                                    : 1 280 pixels
Height                                   : 720 pixels
Display aspect ratio                     : 16:9
Frame rate mode                          : Constant
Frame rate                               : 30.000 fps
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Bits/(Pixel*Frame)                       : 0.109
Stream size                              : 22.7 MiB (92%)
Writing library                          : x264 core 120 r2151 a3f4407
Encoding settings                        : cabac=0 / ref=3 / deblock=1:0:0 / analyse=0x1:0x111 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=0 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=12 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=0 / weightp=0 / keyint=250 / keyint_min=25 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=abr / mbtree=1 / bitrate=3000 / ratetol=1.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00 

It introduced a Muxing mode parameter with level 3.1 but alas this stream did not play on the device either. How do I correct the level indicated in Format Profile Is this possible without re-encoding?

2
What level is set now and what level is needed? Can you post mediainfo of some files?osgx
Its set to 3.0 and I want it to be 3.1, They are all 720p videos.d33pika

2 Answers

1
votes

Note that level is there on format descriptor, and also possibly duplicated on the payload itself. If you don't care about actual integrity of descriptor itself and the payload/encoding (I suppose it's fine to raise level, it might be not okay to lower it though), it is possible to change level without reencoding video.

More than that It is possible to do it both ways, by locating box that holding video track descriptor and patching the level by right there - you won't need FFmpeg, you rather access bytes directly and MP4 format is perhaps simple enough to do it from plain code.

Or, you need to re-multiplex the tracks changing format on the way. Demultiplexers and multiplexers don't do checks to tell whether this level value is acceptable or not, so patching it as a part of re-multiplexing with FFmpeg is workable. Any sample FFmpeg code that does writing to MP4 without re-encoding would be a good start (your task will be to update byte array pointed to by extradata field before opening AVFormatContext).

1
votes

I found a solution, a big credit goes to @Roman for helping me figuring this out. Find the Profile and Level after avcC atom in the mp4 bitstream, in my case this was 42 C0 1E , [email protected], I wanted the level to be 3.1. To do this find all occurrences of 42 C0 1E in the stream and replace 1E with 1F. I found about 8-10 such occurrences. And now you have [email protected]. This can be verified using mediainfo. I think this is necessary because h.264 is encoded as a bunch of packets, and each of them have SPS header with profile and level information.