tsMuxer icon indicating copy to clipboard operation
tsMuxer copied to clipboard

Flush too early causing extra frame to be created

Open moveman opened this issue 3 years ago • 2 comments

The following code in MPEGStreamReader::readPacket() assumed at the end of the H264 stream, there is a NAL unit (such as filler data) after the last picture:

  uint8_t* nextNal = NALUnit::findNALWithStartCode((std::min)(m_curPos + 3, m_bufEnd), m_bufEnd, m_longCodesAllowed);
    if (nextNal == m_bufEnd)
    {
        storeBufferRest();
        return NEED_MORE_DATA;
    }

If there are no such filler data NAL unit, it will return NEED_MORE_DATA.

This in turn caused m_codecInfo[minDtsIndex].m_lastAVRez to be changed:

                if (m_codecInfo[minDtsIndex].lastReadRez != BufferedFileReader::DATA_EOF2)
                {
                    int res = m_codecInfo[minDtsIndex].m_streamReader->readPacket(avPacket);
                    m_codecInfo[minDtsIndex].m_lastAVRez = res;
                }

metaDemuxer has already had m_isEOF set to 1 because all bytes of the H264 stream has been read. Having m_lastAVRez set to NEED_MORE_DATA will cause StreamInfo::read() to return DATA_EOF2:

    if (m_lastAVRez != 0)
    {
        if (m_isEOF)
        {
            m_blockSize = 0;
            return BufferedFileReader::DATA_EOF2;
        }
        m_lastAVRez = 0;

This will cause MetaDemuxer to flush packet METADemuxer::readPacket():

                if (m_codecInfo[minDtsIndex].lastReadRez != BufferedFileReader::DATA_EOF2)
                {
                    int res = m_codecInfo[minDtsIndex].m_streamReader->readPacket(avPacket);
                    m_codecInfo[minDtsIndex].m_lastAVRez = res;
                }
                else
                {
                    // flush single stream
                    m_codecInfo[minDtsIndex].m_streamReader->flushPacket(avPacket);
                    m_codecInfo[minDtsIndex].m_flushed = true;
                }

When flushPacket is called, PTS changed:

// MPEGStreamReader::flushPacket():
    avPacket.pts = m_curPts + m_timeOffset;
    avPacket.dts = m_curDts + m_timeOffset - m_pcrIncPerFrame * getFrameDepth();  // shift dts back

When PTS changes, PES packet will be flushed in TSMuxer::muxPacket():

    if (avPacket.dts != m_streamInfo[tsIndex].m_dts || avPacket.pts != m_streamInfo[tsIndex].m_pts ||
        tsIndex != m_lastTSIndex || avPacket.flags & AVPacket::FORCE_NEW_FRAME)
    {
        writePESPacket();
        newPES = true;
    }

Since the last picture has not been muxed yet, another PES will be created. Outcome will be like this: For the last picture, two PES will be created. One contains the NAL units enclosed by the red circle; another contains the NAL units enclosed by the gray circle: image

Workaround to this problem seems to be always adding filler data to the end of the H264 stream.

moveman avatar Aug 01 '22 02:08 moveman

@moveman can you please copy your .meta file ? I am not clear on the issue, is it the last frame that is copied twice, or is it simply the AUD nal which is wrongfully added ?

jcdr428 avatar Aug 13 '22 14:08 jcdr428

@jcdr428 this is the .meta file:

MUXOPT --no-pcr-on-video-pid --cbr --bitrate=5606.25 --vbv-len=3000 --start-time=62950
V_MPEG4/ISO/AVC, "/mnt/job/77c0fa26-cd8d-4611-919b-171777c52eda/1video.h264"
A_AAC, "/mnt/job/77c0fa26-cd8d-4611-919b-171777c52eda/1_0.aac", timeshift=0ms, , lang=eng

The last frame is not copied twice. AUD nal is wrongly added to the last frame. In addition, this last frame has two PTS instead of one PTS.

moveman avatar Aug 23 '22 02:08 moveman