lieff / minimp4

Minimalistic MP4 mux/demux single header library
Creative Commons Zero v1.0 Universal
345 stars 59 forks source link

Assumes correct SPS/PPS #2

Closed Syd76 closed 5 years ago

Syd76 commented 5 years ago

for work on Nvidia embedded Jetson solution , i switch off MINIMP4_TRANSCODE_SPS_ID and fix compilation.

So, i cant make a readable files with more than 4Go ... Beyond that , in MediaInfo , isTruncated status become TRUE and the file is unreadable into VLC/Mplayer.

I forgot something in code ?

lieff commented 5 years ago

Thanks for the issue :) Can you try -D_FILE_OFFSET_BITS=64 (and check that fseek supports 64bit offsets). If 64bit offsets is supported but still does not work, try sequential_mode = 1 to check if only one mode is broken.

Syd76 commented 5 years ago

the callback use int fseeko(FILE *stream, off_t offset, int whence) i check fseeko on 64bit and trace write_pos value , i can make 40Go file ... but i cant read that.. i go try sequential_mode=1 next day.

lieff commented 5 years ago

For fseeko -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE is correct switches I think. Sample app may produce 40Gb file without 64bit seek support, depending if it fails on offsets >32bit or wraps.

Syd76 commented 5 years ago

sequential_mode = 1 works on i7 / ubuntu 64bits i see a memory arrangement with sequential_mode = 1 , but i'm not an expert on MP4/h264 muxing. what's difference between sequential_mode = 1 and sequential_mode = 0 ? Can i use sequential_mode = 1 for an encoder which use correct SPS/PPS ID's ?

lieff commented 5 years ago

Thanks for testing :) sequential_mode = 1 is what you need then. This two modes have following differences: sequential_mode = 1 guarantees that write/seek always goes forward and never goes back, i.e. streaming move. It also creates BOX_mdat atom per sample and less efficient.

sequential_mode = 0 writes all data to one big BOX_mdat and needs going back to update it's size (stored near beginning of file) when write to mp4 is finished. Here we have overflow, because minimp4 do not support writing BOX_mdat > 4Gb:

    if (!mux->sequential_mode_flag)
    {
        // update size of mdat box.
        // The only point, which requires random file access.
        // This can be avoided using "till eof" size code, but in this case indexes must be
        // written before the mdat....
        WRITE_4(mux->write_pos - sizeof(box_ftyp));
        WRITE_4(BOX_mdat);
        mux->write_callback(sizeof(box_ftyp), base, p-base, mux->token);
        p = base;
    }

I think I'm insert assert here...

lieff commented 5 years ago

Also this two modes have noting to do with SPS/PPS, but mp4 stores SPS/PPS per track and do not support changing it in the middle of stream on fly. That's MINIMP4_TRANSCODE_SPS_ID is for: some hardware encoders changes SPS/PPS ids on fly despite fact that different id point to same copy of SPS/PPS (otherwise stream can't be correctly stored in mp4 at all). When enabled, it transcodes SPS/PPS ids so it always point to copy included in track metadata.

Syd76 commented 5 years ago

Thank for your explains !!! I go to enable sequential_mode and check Nvidia Encoder for SPS/PPS asap ;)

lieff commented 5 years ago

Theoretically, we can create BOX_mdat > 4G for sequential_mode = 0, but problem is, that we must reserve space for it and I'm not sure that use 64bit size encoding for 32bit is right thing to do, some demuxers may support only 32bit.

Syd76 commented 5 years ago

I can capture in h264 file and build a MP4 file with MINIMP4 . that's work for read : sequential_mode = 0 , MINIMP4_TRANSCODE_SPS_ID = 0 and MINIMP4_ALLOW_64BIT = 1

I replace code in case MINIMP4_TRANSCODE_SPS_ID == 0 with : ` payload_type = nal[0] & 31;

        switch (payload_type) {
            case 7:

                MP4E__set_sps(h->mux, h->mux_track_id, nal, sizeof_nal);
                h->need_pps = 1;
                h->need_idr = 1;
                break;
            case 8:
                if (h->mux_track_id == -1)
                    return 0;
                MP4E__set_pps(h->mux, h->mux_track_id, nal, sizeof_nal);

                h->need_pps = 0;
                break;
            case 5:
                if (h->mux_track_id == -1)
                    return 0;
                h->need_idr = 0;

                // flow through
            default:
                if (h->mux_track_id == -1)
                    return 0;

                 if (!h->need_pps && !h->need_idr)
                 {
                    unsigned char *tmp = (unsigned char *)malloc(4 + sizeof_nal);
                    if (tmp)
                    {
                        tmp[0] = (unsigned char)(sizeof_nal >> 24);
                        tmp[1] = (unsigned char)(sizeof_nal >> 16);
                        tmp[2] = (unsigned char)(sizeof_nal >>  8);
                        tmp[3] = (unsigned char)(sizeof_nal);

                        memcpy(tmp + 4, nal, sizeof_nal);
                        MP4E__put_sample(h->mux, h->mux_track_id, tmp,  4+sizeof_nal, timeStamp90kHz_next , payload_type == 5 ); // 
                        free(tmp);
                    }
                }
                break;
        }

` That's use one track id.

But, if i muxing with minimp4 a h264 buffer from capture into MP4 file there are an error message in vlc or avidemux: "sps_id 32 out of range" and "extradataSize:33" , and i cant read than more 4Go.

[[decoderFFH264] 13:11:11-539 [lavc] Initializing H264 decoder with 33 extradata [adm_lavLogCallback] 13:11:11-539 [lavc] The 'vismv' option is deprecated, see the codecview filter instead. [adm_lavLogCallback] 13:11:11-539 [lavc] sps_id 32 out of range [adm_lavLogCallback] 13:11:11-539 [lavc] SPS decoding failure, trying again after escaping the NAL [adm_lavLogCallback] 13:11:11-539 [lavc] sps_id 32 out of range [adm_lavLogCallback] 13:11:11-539 [lavc] Decoding sps 1 from avcC failed

lieff commented 5 years ago

That's expected, sps_id=32 encoded in slice headers. But in track metadata contains only one SPS/PPS arrived first (and probably sps_id=0). That's exactly problem described above and looks like MINIMP4_TRANSCODE_SPS_ID=1 is needed for this encoder. Does it works with MINIMP4_TRANSCODE_SPS_ID=1 sequential_mode = 1 without any modifications?

lieff commented 5 years ago

After https://github.com/lieff/minimp4/commit/8d91f27feeffe46e0e6c16659ee190ab2ed8822b sequential_mode=0 should work with >4Gb too.

Syd76 commented 5 years ago

When i used MINIMP4_TRANSCODE_SPS_ID = 1 , there are a buffer error :

`

0 0x0000007fb7b19528 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54

1 0x0000007fb7b1a9e0 in __GI_abort () at abort.c:89

2 0x0000007fb7b12c04 in __assert_fail_base (fmt=0x7fb7bff290 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x7fb7f95ba8 "n > 0 && n <= 16",

file=file@entry=0x7fb7f958c8 "./src/minimp4.cpp", line=line@entry=1262, 
function=function@entry=0x7fb7f962c0 <show_bits(bit_reader_t*, int)::__PRETTY_FUNCTION__> "unsigned int show_bits(bit_reader_t*, int)") at assert.c:92

3 0x0000007fb7b12cac in __GI___assert_fail (assertion=0x7fb7f95ba8 "n > 0 && n <= 16", file=0x7fb7f958c8 "./src/minimp4.cpp", line=1262,

function=0x7fb7f962c0 <show_bits(bit_reader_t*, int)::__PRETTY_FUNCTION__> "unsigned int show_bits(bit_reader_t*, int)") at assert.c:101

4 0x0000007fb7f6bd04 in show_bits (bs=0x7f6d530408, n=33) at ./src/minimp4.cpp:1262

5 0x0000007fb7f6be58 in get_bits (bs=0x7f6d530408, n=33) at ./src/minimp4.cpp:1282

6 0x0000007fb7f6c084 in ue_bits (bs=0x7f6d530408) at ./src/minimp4.cpp:1332

7 0x0000007fb7f6c93c in change_sps_id (bs=0x7f6d530408, bd=0x7f6d5303d8, new_id=0, old_id=0x7f6d5303c0) at ./src/minimp4.cpp:1544

8 0x0000007fb7f6cc60 in transcode_nalu (h=0x469200, src=0x7f580021f0 "gd\f)", nalu_bytes=4, dst=0x7f58000940 "g!") at ./src/minimp4.cpp:1617

9 0x0000007fb7f6d304 in mp4_h264_write_nal (h=0x469200, nal=0x7f6400c014 "gd\f)\254,\250\003\300\004>@", length=8, timeStamp90kHz_next=9000)

at ./src/minimp4.cpp:1783

`

Syd76 commented 5 years ago

nice job , that's works with options :

I can read the video file (4.2Go) with VLC.

Only a VLC warning in start:

[h264 @ 0x7f6c7cc57d80] illegal POC type 10 [h264 @ 0x7f6c7cc57d80] sps_id 32 out of range [h264 @ 0x7f6c7cc57d80] illegal POC type 10

problems in "Picture Order Count" for first frame, may be something to unsuitable on my modification.

But i cant open file with avidemux

Assert failed :0 at line 589, file /home/syd/usr/share/avidemux_2.7.0/avidemux_core/ADM_coreVideoCodec/src/ADM_ffmp43.cpp ADM_backTrack ADM_coreCodecGetDecoder(unsigned int, unsigned int, unsigned int, unsigned int, unsigned char, unsigned int) ADM_EditorSegment::addReferenceVideo(_VIDEOS) ADM_Composer::addFile(char const) A_openVideo(char const) avidemux3_qt5() [0x48e342] automation() QMetaObject::activate(QObject*, int, int, void) QTimer::timerEvent(QTimerEvent) QObject::event(QEvent) QApplicationPrivate::notify_helper(QObject, QEvent) QApplication::notify(QObject, QEvent) QCoreApplication::notifyInternal(QObject, QEvent) QTimerInfoList::activateTimers() g_main_context_dispatch g_main_context_iteration QEventDispatcherGlib::processEvents(QFlags) QEventLoop::exec(QFlags) QCoreApplication::exec() UI_RunApp() startAvidemux(int, char) main __libc_start_main _start

with a Window Warning _"codec : internal error opening AV_CODEC_IDH264"

lieff commented 5 years ago

Can you attach sample h264 elementary stream that shows the problem?

Syd76 commented 5 years ago

i try git clone with MINIMP4_TRANSCODE_SPS_ID=1 , sequential_mode = 0 left-20181204_0844.zip there a a crash.

In my code , with MINIMP4_TRANSCODE_SPS_ID = 0, i can make more than 4 Go ( sequence 1 or 0 ) , but , VLC read last frame before 4Go. For example, 40Mbits/s ... after 15 minutes, we can see another frame (like a freeze). But, i can open , read and see the time in bottom .

Log VLC after read more than 4Go ( ~ 4.2 go ) :

[h264 @ 0x7f8b60e5fa80] AVC: nal size 1253811430 [h264 @ 0x7f8b60e5fa80] AVC: nal size 1253811430 [h264 @ 0x7f8b60e5fa80] no frame! [h264 @ 0x7f8b60d77f80] AVC: nal size -1752346598 [h264 @ 0x7f8b60d77f80] AVC: nal size -1752346598

Last day , it's was MINIMP4_TRANSCODE_SPS_ID=0 , not MINIMP4_TRANSCODE_SPS_ID=1

lieff commented 5 years ago

Thanks for testing again :) Problem in your stream is zeros at the end of nals, https://github.com/lieff/minimp4/commit/add16550aa10fd96d22f133476d32cc5c3a96b71 should fix it. And now I can open resulting file using avidemux.

Syd76 commented 5 years ago

yes, the function _remove_nalescapes return 0 due buffer problems. i drop buffers and open with avidemux. Thanks

Syd76 commented 5 years ago

Amazing, MINIMP4_TRANSCODE_SPS_ID=1 ans sequence = 0 ... i have an error from id SPS. In change_sps_id function , ue_bits return 33 !!!

Line in git : L2169 : transcode_nalu ... L2000 : int cb = change_sps_id(bst, bdt, 0, &old_id); L1927 : sps_id = ue_bits(bs); // max = 31

here , we have sizeof_nal = 4.

unfortunely , i cant reproduct this in a 264 file.

0 0x0000007fb7b18528 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54

1 0x0000007fb7b199e0 in __GI_abort () at abort.c:89

2 0x0000007fb7b11c04 in __assert_fail_base (fmt=0x7fb7bfe290 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=assertion@entry=0x7fb7f96118 "n > 0 && n <= 16",

file=file@entry=0x7fb7f95e20 "./src/minimp4.cpp", line=line@entry=1225, function=function@entry=0x7fb7f96c38 "unsigned int show_bits(bit_reader_t*, int)") at assert.c:92

3 0x0000007fb7b11cac in __GI___assert_fail (assertion=0x7fb7f96118 "n > 0 && n <= 16", file=0x7fb7f95e20 "./src/minimp4.cpp", line=1225,

function=0x7fb7f96c38 "unsigned int show_bits(bit_reader_t*, int)") at assert.c:101

4 0x0000007fb7f6aed8 in show_bits (bs=0x7f6cd2f408, n=33) at ./src/minimp4.cpp:1225

5 0x0000007fb7f6b02c in get_bits (bs=0x7f6cd2f408, n=33) at ./src/minimp4.cpp:1245

6 0x0000007fb7f6b268 in ue_bits (bs=0x7f6cd2f408) at ./src/minimp4.cpp:1297

7 0x0000007fb7f6bb30 in change_sps_id (bs=0x7f6cd2f408, bd=0x7f6cd2f3d8, new_id=0, old_id=0x7f6cd2f3c0) at ./src/minimp4.cpp:1511

8 0x0000007fb7f6be54 in transcode_nalu (h=0x469200, src=0x7f580020e0 "gd\f)", nalu_bytes=4, dst=0x7f58000940 "g ") at ./src/minimp4.cpp:1584

9 0x0000007fb7f6c56c in mp4_h264_write_nal (h=0x469200, nal=0x7f440009c4 "gd\f)\254,\250\003\300\004>@", length=8, timeStamp90kHz_next=9000)

at ./src/minimp4.cpp:1768

10 0x0000007fb7f3083c in Nv_MJPEG_Encoder_HEVC::write_HEVC_Context (this=0x45ba20, _ctx=0x468a90, _frame=0x7f440008c0)

at ./src/Nv_MJPEG_Encoder_HEVC.cpp:7619

Syd76 commented 5 years ago

THX .... i think that i found for SPS error out of rang ( 33 > 31 ) ... that's a NvVideoEncoder setting profile : set to HIGH. So , _MINIMP4_TRANSCODE_SPS_ID = 1 doesn't crash !!!

lieff commented 5 years ago

Nice :) I will try to check big files as well.

Syd76 commented 5 years ago

I add free buffer in cas :

`

        if( !sizeof_nal )
        {
            free(nal1);
            free(nal2);
            return 0;
        }

`

_MINIMP4_TRANSCODE_SPSID = 1 and Sequence = 0 , there are a freeze image in VLC with message :

[h264 @ 0x7fe444def5c0] AVC: nal size -492798288 [h264 @ 0x7fe444def5c0] AVC: nal size -492798288 [h264 @ 0x7fe444def5c0] no frame! [h264 @ 0x7fe444d07ac0] AVC: nal size -1061128795 [h264 @ 0x7fe444d07ac0] AVC: nal size -1061128795 [h264 @ 0x7fe444d07ac0] no frame! [h264 @ 0x7fe444d60680] AVC: nal size 2006677627 [h264 @ 0x7fe444d60680] AVC: nal size 2006677627 [h264 @ 0x7fe444d60680] no frame!

I think is last image before the 4.2 Go.

_MINIMP4_TRANSCODE_SPSID = 1 and Sequence = 1 have same issu

lieff commented 5 years ago

Thanks :) Fixed the leak.

Syd76 commented 5 years ago

It's more me who thank you !!!

Have you an idea for read big files ? I can read first 4.2Go on big file. All other frames after this was mark go away like vlc message , but scrollbar time run always.

[h264 @ 0x7fe444def5c0] AVC: nal size -492798288 [h264 @ 0x7fe444def5c0] no frame!

lieff commented 5 years ago

Here 64bit indexes support https://github.com/lieff/minimp4/commit/cced14d26dbfa07b2d12b50f553fb6fc70db1d42 . Now I'm able to seek large files.

Syd76 commented 5 years ago

nice job !!!! ... i make big MP4 file with sample left-20181204_0844.zip (loop in minimp4_test.c for duplicate h264 buffer)... and, that's work well ;) Tomorrow , i try with camera .... i thinks that will be good ! :)

This is a tiny application is great job for small soc and embedded system :1st_place_medal:

lieff commented 5 years ago

Can you check that High Profile works too? If it's not, can you attach sample stream?

Syd76 commented 5 years ago

i think left-20181204_0844.zip is on 10fps, 4k , profile HIGH and level 4.0 , i will to test too on 5.1 for next nigth

lieff commented 5 years ago

I'm about

THX .... i think that i found for SPS error out of rang ( 33 > 31 ) ... that's a NvVideoEncoder setting profile : set to HIGH.

left-20181204_0844.zip do not have such problem. This can be issue with sps rbsp encoding. Or that was error not HP related?

Syd76 commented 5 years ago

sps id from encoding was solve with good parameters settings on Hardware HEVC (encoder like sps enable option --' ). Today , that's ok ! And this seems to work in level 5.1. ( profile HIGH)

lieff commented 5 years ago

Good :) I guess everything solved then.

Syd76 commented 5 years ago

:1st_place_medal:

Yep ... nice job !!!

Syd76 commented 5 years ago

Last nightly, tests have work well in level 5.1 , and have produced readable big files !!!

That's solved ;)

lieff commented 5 years ago

Closing then.