lieff / minimp4

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

fragmentation mode + slices doesn't work #15

Open rhwu opened 4 years ago

rhwu commented 4 years ago

./minimp4_x86 -f test.264 test-f.mp4 ./minimp4_x86 -s test.264 test-s.mp4 ./minimp4_x86 test.264 test.mp4

test-s.mp4 and test.mp4 looks fine. But test-f.mp4 is broken. test-f.mp4 and test.264 (1920x1080) attached. test.zip

lieff commented 4 years ago

This is sliced h264 stream. As already mentioned here https://github.com/lieff/minimp4/issues/16 fragmentation+slices mode currently not supported by mp4_h26x_write_nal helper. Will do it at some point too.

autoexpect commented 1 year ago

I tried to modify this function,

static int mp4_h265_write_nal(mp4_h26x_writer_t *h, const unsigned char *nal, int sizeof_nal, unsigned timeStamp90kHz_next)
{
    int payload_type = (nal[0] >> 1) & 0x3f;
    int slice_type;
    int is_intra = payload_type >= HEVC_NAL_BLA_W_LP && payload_type <= HEVC_NAL_CRA_NUT;
    int err = MP4E_STATUS_OK;
    //printf("payload_type=%d, intra=%d\n", payload_type, is_intra);

    if (is_intra && !h->need_sps && !h->need_pps && !h->need_vps)
        h->need_idr = 0;
    switch (payload_type)
    {
    case HEVC_NAL_VPS:
        MP4E_set_vps(h->mux, h->mux_track_id, nal, sizeof_nal);
        h->need_vps = 0;
        break;
    case HEVC_NAL_SPS:
        MP4E_set_sps(h->mux, h->mux_track_id, nal, sizeof_nal);
        h->need_sps = 0;
        break;
    case HEVC_NAL_PPS:
        MP4E_set_pps(h->mux, h->mux_track_id, nal, sizeof_nal);
        h->need_pps = 0;
        break;
    default:
        if (h->need_vps || h->need_sps || h->need_pps || h->need_idr)
            return MP4E_STATUS_BAD_ARGUMENTS;
        {
            unsigned char *tmp = (unsigned char *)malloc(4 + sizeof_nal);
            if (!tmp)
                return MP4E_STATUS_NO_MEMORY;
            int sample_kind = MP4E_SAMPLE_DEFAULT;
            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);
            if (is_intra) {
                slice_type = (nal[2] >> 2) & 0x07;
                if (slice_type != 3) {
                    sample_kind = MP4E_SAMPLE_CONTINUATION;
                } else {
                    sample_kind = MP4E_SAMPLE_RANDOM_ACCESS;
                }
            } else {
                slice_type = (nal[2] >> 3) & 0x07;
                if (slice_type != 2) {
                    sample_kind = MP4E_SAMPLE_CONTINUATION;
                } else {
                    sample_kind = MP4E_SAMPLE_DEFAULT;
                }
            }
            err = MP4E_put_sample(h->mux, h->mux_track_id, tmp, 4 + sizeof_nal, timeStamp90kHz_next, sample_kind);
            free(tmp);
        }
        break;
    }
    return err;
}

maybe i need to fix the mp4e_write_fragment_header function too...

    else if (kind == MP4E_SAMPLE_CONTINUATION)
    {
        flags = 0;
        flags |= 0x001; // data-offset-present
        flags |= 0x004; // first-sample-flags-present
        flags |= 0x100; // sample-duration-present
        flags |= 0x200; // sample-size-present
        ATOM_FULL(BOX_trun, flags)
        WRITE_4(1); // sample_count
        pdata_offset = p;
        p += 4;              // save ptr to data_offset
        WRITE_4(0x2000000);  // first_sample_flags
        WRITE_4(duration);   // sample_duration
        WRITE_4(data_bytes); // sample_size
        END_ATOM
    }