Esempio n. 1
0
// Return TRUE if all was read.  FALSE if a problem occured:
// If a bitstream syntax problem occured the bitstream will
// point to after the problem, in case we run out of data the bitstream
// will point to where we want to restart after getting more.
static int read_pic_data(struct bitstream *esstream)
{
    dbg_print(DMT_VERBOSE, "Read PIC Data\n");

    uint8_t startcode = next_start_code(esstream);

    // Possibly the last call to this function ended with the last
    // bit of the slice? I.e. in_pic_data is still true, but we are
    // seeing the next start code.

    // We only get here after seeing that start code
    if (startcode < 0x01 || startcode > 0xAF)
    {
        dbg_print(DMT_VERBOSE, "Read Pic Data - processed0\n");

        return 1;
    }

    // If we get here esstream points to the start of a slice_start_code
    // should we run out of data in esstream this is where we want to restart
    // after getting more.
    unsigned char *slice_start = esstream->pos;

    do
    {
        startcode = next_start_code(esstream);
        // Syntax check
        if (startcode == 0xB4)
        {
            if (esstream->bitsleft < 0)
                init_bitstream(esstream, slice_start, esstream->end);

            if ( esstream->error )
                dbg_print(DMT_VERBOSE, "read_pic_data: syntax problem.\n");
            else
                dbg_print(DMT_VERBOSE, "read_pic_data: reached end of bitstream.\n");

            return 0;
        }

        slice_start = esstream->pos; // No need to come back

        if ( startcode >= 0x01 && startcode <= 0xAF )
        {
            read_u32(esstream); // Advance bitstream
            search_start_code(esstream); // Skip this slice
        }
    }
    while(startcode >= 0x01 && startcode <= 0xAF);

    if (esstream->bitsleft < 0)
    {
        init_bitstream(esstream, slice_start, esstream->end);
        return 0;
    }

    dbg_print(DMT_VERBOSE, "Read Pic Data - processed\n");

    return 1;
}
Esempio n. 2
0
const unsigned char* H264FileReader::ReadNextFrame()
{
    size_t n = 0;
    const unsigned char* p;
    assert(m_ptr+m_offset == search_start_code(m_ptr+m_offset, m_bytes-m_offset));
    
    do
    {
        p = search_start_code(m_ptr + m_offset + 3, m_bytes - m_offset - 3);
        if(!p)
        {
            if(m_offset > 0)
            {
                memmove(m_ptr, m_ptr+m_offset, m_bytes-m_offset);
                m_bytes -= m_offset;
                m_offset = 0;

                // try read file
                assert(m_bytes < m_capacity);
                n = fread(m_ptr + m_bytes, 1, m_capacity - m_bytes, m_fp);
                m_bytes += n;
            }
            else
            {
                // 1. more memory
				unsigned char* ptr = NULL;
                ptr = (unsigned char*)realloc(m_ptr, m_capacity + m_capacity/2);
                if(ptr)
                {
					m_ptr = ptr;
                    m_capacity += m_capacity/2;

                    // 2. read file
                    assert(0 == m_offset);
                    n = fread(m_ptr + m_bytes, 1, m_capacity - m_bytes, m_fp);
                    m_bytes += n;
                }
				else
				{
					break; // don't have enough memory
				}
            }
        }
    } while(!p && m_ptr && m_capacity < 10*1024*1024 && n > 0); // Max frame size 10MB
    
    return p;
}
Esempio n. 3
0
int H264FileReader::Init()
{
	//assert(IsOpened());
	//assert(0 == ftell(m_fp));
    assert(m_ptr == search_start_code(m_ptr, m_bytes));

	long offset = 0;
    size_t count = 0;
    bool spspps = true;
    const unsigned char* nalu = m_ptr;

	do
	{
        const unsigned char* nalu2 = ReadNextFrame();

		nalu = m_ptr + m_offset;
        int nal_unit_type = h264_nal_type(nalu);
        assert(0 != nal_unit_type);
        if(nal_unit_type <= 5)
        {
            if(m_sps.size() > 0) spspps = false; // don't need more sps/pps

			long n = ftell(m_fp);

			vframe_t frame;
			frame.offset = offset;
			frame.bytes = (nalu2 ? toOffset(nalu2) : n) - offset;
			frame.time = 40 * count++;
			frame.idr = 5 == nal_unit_type; // IDR-frame
			m_videos.push_back(frame);
			offset += frame.bytes;
        }
        else if(NAL_SPS == nal_unit_type || NAL_PPS == nal_unit_type)
        {
            assert(nalu2);
            if(spspps && nalu2)
            {
                size_t n = 0x01 == nalu[2] ? 3 : 4;
                sps_t sps(nalu2 - nalu - n);
                memcpy(&sps[0], nalu+n, nalu2-nalu-n);

				// filter last 0x00 bytes
				while(sps.size() > 0 && !*sps.rbegin())
					sps.resize(sps.size()-1);
				m_sps.push_back(sps);
            }
        }

        nalu = nalu2;
        m_offset = nalu - m_ptr;
    } while(nalu);

    m_duration = 40 * count;
    return 0;
}
Esempio n. 4
0
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int extension_and_user_data(struct bitstream *esstream, int udtype)
{
    dbg_print(DMT_VERBOSE, "Extension and user data(%d)\n", udtype);

    if (esstream->error || esstream->bitsleft <= 0)
        return 0;

    // Remember where to continue
    unsigned char *eau_start = esstream->pos;

    uint8_t startcode;

    do
    {
        startcode = next_start_code(esstream);

        if ( startcode == 0xB2 || startcode == 0xB5 )
        {
            read_u32(esstream); // Advance bitstream
            unsigned char *dstart = esstream->pos;

            // Advanve esstream to the next startcode.  Verify that
            // the whole extension was available and discard blocks
            // followed by PACK headers.  The latter usually indicates
            // a PS treated as an ES. 
            uint8_t nextstartcode = search_start_code(esstream);
            if (nextstartcode == 0xBA)
            {
                mprint("\nFound PACK header in ES data. Probably wrong stream mode!\n");
                esstream->error = 1;
                return 0;
            }

            if (esstream->error)
            {
                dbg_print(DMT_VERBOSE, "Extension and user data - syntax problem\n");
                return 0;
            }

            if (esstream->bitsleft < 0)
            {
                dbg_print(DMT_VERBOSE, "Extension and user data - inclomplete\n");
                // Restore to where we need to continue
                init_bitstream(esstream, eau_start, esstream->end);
                esstream->bitsleft = -1; // Redundant
                return 0;
            }

            if (startcode == 0xB2)
            {
                struct bitstream ustream;
                init_bitstream(&ustream, dstart, esstream->pos);
                user_data(&ustream, udtype);
            }
            else
            {
                dbg_print(DMT_VERBOSE, "Skip %d bytes extension data.\n",
                           esstream->pos - dstart);
            }
            // If we get here esstream points to the end of a block
            // of extension or user data.  Should we run out of data in
            // this loop this is where we want to restart after getting more.
            eau_start = esstream->pos;
        }
    }
    while(startcode == 0xB2 || startcode == 0xB5);

    if (esstream->error)
    {
        dbg_print(DMT_VERBOSE, "Extension and user data - syntax problem\n");
        return 0;
    }
    if (esstream->bitsleft < 0)
    {
        dbg_print(DMT_VERBOSE, "Extension and user data - inclomplete\n");
        // Restore to where we need to continue
        init_bitstream(esstream, eau_start, esstream->end);
        esstream->bitsleft = -1; // Redundant
        return 0;
    }

    dbg_print(DMT_VERBOSE, "Extension and user data - processed\n");

    // Read complete
    return 1;
}
Esempio n. 5
0
// Return TRUE if the video sequence was finished, FALSE
// Otherwise.  estream->pos shall point to the position where
// the next call will continue, i.e. the possible begin of an
// unfinished video sequence or after the finished sequence.
static int es_video_sequence(struct bitstream *esstream)
{
    // Avoid "Skip forward" message on first call and later only
    // once per search.
    static int noskipmessage = 1;
    uint8_t startcode;

    dbg_print(DMT_VERBOSE, "es_video_sequence()\n");

    esstream->error = 0;

    // Analyze sequence header ...
    if (!no_bitstream_error)
    {
        // We might start here because of a syntax error. Discard
        // all data until a new sequence_header_code or group_start_code
        // is found.

        if (!noskipmessage) // Avoid unnecessary output.
            mprint("\nSkip forward to the next Sequence or GOP start.\n");
        else
            noskipmessage = 0;

        uint8_t startcode;
        while(1)
        {
            // search_start_code() cannot produce esstream->error
            startcode = search_start_code(esstream);
            if (esstream->bitsleft < 0)
            {
                noskipmessage = 1;
                return 0;
            }

            if (startcode == 0xB3 || startcode == 0xB8) // found it
                break;

            skip_bits(esstream, 4*8);
        }

        no_bitstream_error = 1;
        saw_seqgoppic = 0;
        in_pic_data = 0;
    }

    do
    {
        startcode = next_start_code(esstream);

        dbg_print(DMT_VERBOSE, "\nM2V - next start code %02X %d\n", startcode, in_pic_data);

        // Syntax check - also returns on bitsleft < 0
        if (startcode == 0xB4)
        {
            if (esstream->error)
            {
                no_bitstream_error = 0;
                dbg_print(DMT_VERBOSE, "es_video_sequence: syntax problem.\n");
            }

            dbg_print(DMT_VERBOSE, "es_video_sequence: return on B4 startcode.\n");

            return 0;
        }

        // Sequence_end_code
        if (startcode == 0xB7)
        {
            read_u32(esstream); // Advance bitstream
            no_bitstream_error = 0;
            break;
        }

        if (!in_pic_data && startcode == 0xB3)
        {
            if (!read_seq_info(esstream))
            {
                if (esstream->error)
                    no_bitstream_error = 0;
                return 0;
            }
            saw_seqgoppic = 1;
            continue;
        }

        if (!in_pic_data && startcode == 0xB8)
        {
            if (!read_gop_info(esstream))
            {
                if (esstream->error)
                    no_bitstream_error = 0;
                return 0;
            }
            saw_seqgoppic = 2;
            continue;
        }

        if (!in_pic_data && startcode == 0x00)
        {
            if (!read_pic_info(esstream))
            {
                if (esstream->error)
                    no_bitstream_error = 0;
                return 0;
            }
            saw_seqgoppic = 3;
            in_pic_data = 1;
            continue;
        }

        // Only looks for extension and user data if we saw sequence, gop
        // or picture info before.
        // This check needs to be before the "in_pic_data" part.
        if ( saw_seqgoppic && (startcode == 0xB2 || startcode == 0xB5))
        {
            if (!read_eau_info(esstream, saw_seqgoppic-1))
            {
                if (esstream->error)
                    no_bitstream_error = 0;
                return 0;
            }
            saw_seqgoppic = 0;
            continue;
        }

        if (in_pic_data) // See comment in read_pic_data()
        {
            if (!read_pic_data(esstream))
            {
                if (esstream->error)
                    no_bitstream_error = 0;
                return 0;
            }
            saw_seqgoppic = 0;
            in_pic_data = 0;
            continue;
        }

        // Nothing found - bitstream error
        if (startcode == 0xBA)
        {
            mprint("\nFound PACK header in ES data.  Probably wrong stream mode!\n");
        }
        else
        {
            mprint("\nUnexpected startcode: %02X\n", startcode);
        }
        no_bitstream_error = 0;
        return 0;
    }
    while(1);

    return 1;
}