예제 #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;
}
예제 #2
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_gop_info(struct bitstream *esstream)
{
    dbg_print(DMT_VERBOSE, "Read GOP Info\n");

    // We only get here after seeing that start code
    if (next_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
        fatal(EXIT_BUG_BUG, "Impossible!");

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

    gop_header(esstream);
    //extension_and_user_data(esstream);

    if (esstream->error)
        return 0;

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

    dbg_print(DMT_VERBOSE, "Read GOP Info - processed\n\n");

    return 1;
}
예제 #3
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_seq_info(struct bitstream *esstream)
{
    dbg_print(DMT_VERBOSE, "Read Sequence Info\n");

    // We only get here after seeing that start code
    if (next_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
        fatal(EXIT_BUG_BUG, "read_seq_info: Impossible!");

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

    sequence_header(esstream);
    sequence_ext(esstream);
    // FIXME: if sequence extension is missing this is not MPEG-2,
    // or broken.  Set bitstream error.
    //extension_and_user_data(esstream);

    if (esstream->error)
        return 0;

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

    dbg_print(DMT_VERBOSE, "Read Sequence Info - processed\n\n");

    return 1;
}
예제 #4
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_gop_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
	debug("Read GOP Info\n");

	// We only get here after seeing that start code
	if (next_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
		fatal(CCX_COMMON_EXIT_BUG_BUG, "read_gop_info: next_u32(esstream) != 0xB8010000. Please file a bug report in GitHub.\n");

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

	gop_header(ctx, esstream, sub);
	//extension_and_user_data(esstream);

	if (esstream->error)
		return 0;

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

	debug("Read GOP Info - processed\n\n");

	return 1;
}
예제 #5
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_seq_info(struct lib_cc_decode *ctx, struct bitstream *esstream)
{
	debug("Read Sequence Info\n");

	// We only get here after seeing that start code
	if (next_u32(esstream) != 0xB3010000) // LSB first (0x000001B3)
		fatal(CCX_COMMON_EXIT_BUG_BUG, "read_seq_info: next_u32(esstream) != 0xB3010000. Please file a bug report in GitHub.\n");

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

	sequence_header(ctx, esstream);
	sequence_ext(ctx, esstream);
	// FIXME: if sequence extension is missing this is not MPEG-2,
	// or broken.  Set bitstream error.
	//extension_and_user_data(esstream);

	if (esstream->error)
		return 0;

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

	debug("Read Sequence Info - processed\n\n");

	return 1;
}
예제 #6
0
파일: h264.cpp 프로젝트: emericg/MiniVideo
/*!
 * \param *media: A pointer to a MediaFile_t structure, containing every informations available about the current media file.
 * \param tid: Track ID.
 * \return A pointer to the newlee allocated DecodingContext.
 *
 * Initialize the DecodingContext and it's bitstream (with a MediaFile_t passed in parameters),
 * then NAL Unit structure, then init all pointer's (sps, pps, sei) to NULL.
 */
DecodingContext_t *initDecodingContext(MediaFile_t *media, unsigned tid)
{
    TRACE_INFO(H264, BLD_GREEN "initDecodingContext()" CLR_RESET);
    DecodingContext_t *dc = NULL;

    if (media != NULL &&
        tid < media->tracks_video_count &&
        media->tracks_video[tid] != NULL)
    {
        // DecodingContext allocation
        dc = (DecodingContext_t*)calloc(1, sizeof(DecodingContext_t));

        if (dc == NULL)
        {
            TRACE_ERROR(H264, "Unable to alloc new DecodingContext!");
        }
        else
        {
            // Select media and track
            dc->MediaFile = media;
            dc->VideoStream = media->tracks_video[tid];
            dc->active_tid = tid;

            // Init some quantization parameters
            computeNormAdjust(dc);

            // Init input bitstream
            dc->bitstr = init_bitstream(media, media->tracks_video[tid]);

            if (dc->bitstr == NULL)
            {
                free(dc);
                dc = NULL;
            }
            else
            {
                // Init NAL Unit
                dc->active_nalu = initNALU();

                if (dc->active_nalu == NULL)
                {
                    free(dc->bitstr);
                    dc->bitstr = NULL;

                    free(dc);
                    dc = NULL;
                }
            }
        }
    }

    // Return the DecodingContext
    return dc;
}
예제 #7
0
/* Process a mpeg-2 data stream with "lenght" bytes in buffer "data".
 * The number of processed bytes is returned.
 * Defined in ISO/IEC 13818-2 6.2 */
LLONG process_m2v (unsigned char *data, LLONG length)
{
    if (length<8) // Need to look ahead 8 bytes
        return length;

    // Init bitstream
    struct bitstream esstream;
    init_bitstream(&esstream, data, data+length);

    // Process data. The return value is ignored as esstream.pos holds
    // the information how far the parsing progressed.
    es_video_sequence(&esstream);

    // This returns how many bytes were processed and can therefore
    // be discarded from "buffer". "esstream.pos" points to the next byte
    // where processing will continue.
    return (LLONG) (esstream.pos - data);
}
예제 #8
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;
}
예제 #9
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_info(struct bitstream *esstream)
{
    dbg_print(DMT_VERBOSE, "Read PIC Info\n");

    // We only get here after seeing that start code
    if (next_u32(esstream) != 0x00010000) // LSB first (0x00000100)
        fatal(EXIT_BUG_BUG, "Impossible!");

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

    pic_header(esstream);
    pic_coding_ext(esstream);

    if (esstream->error)
        return 0;

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

    // Analyse/use the picture information
    static int maxtref; // Use to remember the temporal reference number

    // A new anchor frame - flush buffered caption data. Might be flushed
    // in GOP header already.
    if (picture_coding_type==I_FRAME || picture_coding_type==P_FRAME)
    {		
//		if (((picture_structure != 0x1) && (picture_structure != 0x2)) ||
//		(temporal_reference != current_tref))
//		{
			// NOTE: process_hdcc() needs to be called before set_fts() as it
			// uses fts_now to re-create the timeline !!!!!
			if (has_ccdata_buffered)
			{
	            process_hdcc();
			}
			anchor_hdcc(temporal_reference);
//		}
    }

    current_tref = temporal_reference;
    current_picture_coding_type = picture_coding_type;

    // We mostly use PTS, but when the GOP mode is enabled do not set
    // the FTS time here.
    if (!use_gop_as_pts)
    {
        set_fts(); // Initialize fts
    }

    dbg_print(DMT_VIDES, "PTS: %s (%8u) - tref: %2d - %s  since tref0/GOP: %2u/%2u",
           print_mstime(current_pts/(MPEG_CLOCK_FREQ/1000)),
           unsigned(current_pts), temporal_reference,
       pict_types[picture_coding_type],
           unsigned(frames_since_ref_time),
           unsigned(frames_since_last_gop));
    dbg_print(DMT_VIDES, "  t:%d r:%d p:%d", top_field_first,
           repeat_first_field, progressive_frame);
    dbg_print(DMT_VIDES, "  FTS: %s\n", print_mstime(get_fts()));

    // Set min_pts/sync_pts according to the current time stamp.
    // Use fts_at_gop_start as reference when a GOP header was seen
    // since the last frame 0. If not this is most probably a
    // TS without GOP headers but with USER DATA after each picture
    // header. Use the current FTS values as reference.
    // Note: If a GOP header was present the reference time is from
    // the beginning of the GOP, otherwise it is now.
    if(temporal_reference == 0)
    {
        last_gop_length = maxtref + 1;
        maxtref = temporal_reference;

        // frames_since_ref_time is used in set_fts()

        if( saw_gop_header )
        {
            // This time (fts_at_gop_start) that was set in the
            // GOP header and it might be off by one GOP. See the comment there.
            frames_since_ref_time = frames_since_last_gop; // Should this be 0?
        }
        else
        {
            // No GOP header, use the current values
            fts_at_gop_start=get_fts();
            frames_since_ref_time = 0;
        }

        if (debug_mask & DMT_TIME)
        {
            dbg_print(DMT_TIME, "\nNew temporal reference:\n");
            print_debug_timing();
        }

        saw_gop_header = 0; // Reset the value
    }

    if ( !saw_gop_header && picture_coding_type==I_FRAME )
    {
        // A new GOP beginns with an I-frame. Lets hope there are
        // never more than one per GOP
        frames_since_last_gop = 0;
    }

    // Set maxtref
    if( temporal_reference > maxtref ) {
        maxtref = temporal_reference;
        if (maxtref+1 > max_gop_length)
            max_gop_length = maxtref+1;
    }

    unsigned extraframe = 0;
    if (repeat_first_field)
    {
        pulldownfields++;
        total_pulldownfields++;
        if ( current_progressive_sequence || !(total_pulldownfields%2) )
            extraframe = 1;
        if ( current_progressive_sequence && top_field_first )
            extraframe = 2;
        dbg_print(DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n",
                   total_pulldownfields, extraframe);
    }

    total_pulldownframes += extraframe;
    total_frames_count += 1+extraframe;
    frames_since_last_gop += 1+extraframe;
    frames_since_ref_time += 1+extraframe;

    dbg_print(DMT_VERBOSE, "Read PIC Info - processed\n\n");

    return 1;
}
예제 #10
0
파일: ps.c 프로젝트: seanvk/MiniVideo
/*!
 * \brief Parse a mp4 file.
 * \param *video A pointer to a VideoFile_t structure.
 * \return retcode 1 if succeed, 0 otherwise.
 *
 * This parser is based on the 'ISO/IEC 13818-1' international standard, part 1:
 * 'Transmission multiplexing and synchronization'.
 */
int ps_fileParse(VideoFile_t *video)
{
    TRACE_INFO(MPS, BLD_GREEN "ps_fileParse()\n" CLR_RESET);
    int retcode = SUCCESS;
    int sid = 0;

    // Init bitstream to parse container infos
    Bitstream_t *bitstr = init_bitstream(video, NULL);

    if (bitstr != NULL)
    {
        // Init bitstream_map to store container infos
        retcode = init_bitstream_map(&video->tracks_audio[0], 999999);
        retcode = init_bitstream_map(&video->tracks_video[0], 999999);

        if (retcode == SUCCESS)
        {
            video->tracks_audio[0]->stream_type = stream_AUDIO;
            video->tracks_audio[0]->stream_level = stream_level_PES;
            video->tracks_audio[0]->stream_codec = CODEC_MPEG_L3;
            video->tracks_audio[0]->sample_alignment = false;

            video->tracks_video[0]->stream_type = stream_VIDEO;
            video->tracks_video[0]->stream_level = stream_level_PES;
            video->tracks_video[0]->stream_codec = CODEC_MPEG12;
            video->tracks_video[0]->sample_alignment = false;

            // Read bitstream
            while (retcode == SUCCESS &&
                   (bitstream_get_absolute_byte_offset(bitstr) + 4) < video->file_size &&
                   next_bits(bitstr, 32) != PES_PROGRAM_END)
            {
                PackHeader_t pack_header;
                SystemHeader_t system_header;

                if (read_bits(bitstr, 32) == PES_PACK_HEADER)
                {
                    // Parse pack & system header
                    retcode = parse_pack_header(bitstr, &pack_header, &system_header);

                    // Then loop on PES
                    while (retcode == SUCCESS &&
                           (bitstream_get_absolute_byte_offset(bitstr) + 4) < video->file_size &&
                           next_bits(bitstr, 32) != PES_PACK_HEADER &&
                           next_bits(bitstr, 32) != PES_PROGRAM_END)
                    {
                        // Init
                        PesPacket_t pes_packet;
                        ProgramStreamMap_t pes_streammap;
                        ProgramStreamDirectory_t pes_streamdirectory;

                        // Parse start code
                        pes_packet.packet_start_offset = bitstream_get_absolute_byte_offset(bitstr);
                        pes_packet.packet_start_code   = read_bits(bitstr, 24);
                        pes_packet.stream_id           = (uint8_t)read_bits(bitstr, 8);

                        if (pes_packet.packet_start_code == PES_PACKETSTARTCODE)
                        {
                            switch (pes_packet.stream_id)
                            {
                            case SID_PROGRAM_STREAM_MAP:
                                retcode = parse_program_stream_map(bitstr, &pes_streammap);
                                break;
                            case SID_PROGRAM_STREAM_DIRECTORY:
                                retcode = parse_program_stream_directory(bitstr, &pes_streamdirectory);
                                break;
                            case SID_PADDING:
                                retcode = parse_pes_padding(bitstr, &pes_packet);
                                break;
                            case SID_PRIVATE_STREAM_1:
                                TRACE_2(MPS, BLD_GREEN "Private Stream 1 PES" CLR_RESET " @ %i\n", pes_packet.packet_start_offset);
                                retcode = skip_pes(bitstr, &pes_packet);
                                break;
                            case SID_PRIVATE_STREAM_2:
                                TRACE_2(MPS, BLD_GREEN "Private Stream 2 PES" CLR_RESET " @ %i\n", pes_packet.packet_start_offset);
                                retcode = skip_pes(bitstr, &pes_packet);
                                break;
                            case SID_VIDEO:
                                TRACE_INFO(MPS, BLD_GREEN "parse_pes_video()" CLR_RESET " @ %i\n", pes_packet.packet_start_offset);
                                retcode = parse_pes(bitstr, &pes_packet);
                                //print_pes(&pes_packet);

                                // Set sample into the bitstream_map
                                video->tracks_video[0]->sample_count++;
                                sid = video->tracks_video[0]->sample_count;
                                if (sid < 999999)
                                {
                                    video->tracks_video[0]->sample_type[sid] = sample_VIDEO;
                                    video->tracks_video[0]->sample_size[sid] = pes_packet.PES_packet_length + 6;
                                    video->tracks_video[0]->sample_offset[sid] = pes_packet.packet_start_offset;
                                    video->tracks_video[0]->sample_pts[sid] = pes_packet.PTS;
                                    video->tracks_video[0]->sample_dts[sid] = pes_packet.DTS;
                                }
                                break;
                            case SID_AUDIO:
                                TRACE_INFO(MPS, BLD_GREEN "parse_pes_audio()" CLR_RESET " @ %i\n", pes_packet.packet_start_offset);
                                retcode = parse_pes(bitstr, &pes_packet);
                                //print_pes(&pes_packet);

                                // Set sample into the bitstream_map
                                video->tracks_audio[0]->sample_count++;
                                sid = video->tracks_audio[0]->sample_count;
                                if (sid < 999999)
                                {
                                    video->tracks_audio[0]->sample_type[sid] = sample_AUDIO;
                                    video->tracks_audio[0]->sample_size[sid] = pes_packet.PES_packet_length + 6;
                                    video->tracks_audio[0]->sample_offset[sid] = pes_packet.packet_start_offset;
                                    video->tracks_audio[0]->sample_pts[sid] = pes_packet.PTS;
                                    video->tracks_audio[0]->sample_dts[sid] = pes_packet.DTS;
                                }
                                break;
                            default:
                                TRACE_WARNING(MPS, "Unknown PES type (0x%06X%02X) @ %i\n", pes_packet.packet_start_code, pes_packet.stream_id, pes_packet.packet_start_offset);
                                retcode = skip_pes(bitstr, &pes_packet);
                                break;
                            }
                        }
                        else
                        {
                            TRACE_ERROR(MPS, "No valid packet_start_code at %i\n", pes_packet.packet_start_offset);
                            retcode = FAILURE;
                        }
                    }
                }
                else
                {
                    TRACE_ERROR(MPS, "No pack header\n");
                    retcode = FAILURE;
                }
            }
        }

        // Free bitstream
        free_bitstream(&bitstr);
    }

    return retcode;
}
예제 #11
0
파일: h264.c 프로젝트: seanvk/MiniVideo
/*!
 * \brief Free decoding context.
 * \param *video A pointer to a VideoFile_t structure, containing every informations available about the current video file.
 * \return A pointer to the newlee allocated DecodingContext.
 *
 * Initialize the DecodingContext and it's bitstream (with a VideoFile_t passed in parameters),
 * then NAL Unit structure, then init all pointer's (sps, pps, sei) to NULL.
 */
DecodingContext_t *initDecodingContext(VideoFile_t *video)
{
    TRACE_INFO(H264, BLD_GREEN "initDecodingContext()\n" CLR_RESET);
    DecodingContext_t *dc = NULL;

    if (video != NULL)
    {
        // DecodingContext allocation
        dc = (DecodingContext_t*)calloc(1, sizeof(DecodingContext_t));

        if (dc == NULL)
        {
            TRACE_ERROR(H264, "Unable to alloc new DecodingContext!\n");
        }
        else
        {
            // Init output variables
            dc->output_format = 0;
            dc->picture_quality = 75;
            dc->picture_number = 1;
            dc->picture_extractionmode = 0;

            // Init input bitstream
            dc->VideoFile = video;
            dc->bitstr = init_bitstream(video, video->tracks_video[0]);

            if (dc->bitstr == NULL)
            {
                free(dc);
                dc = NULL;
            }
            else
            {
                // Init NAL Unit
                dc->active_nalu = initNALU();

                if (dc->active_nalu == NULL)
                {
                    free(dc->bitstr);
                    dc->bitstr = NULL;

                    free(dc);
                    dc = NULL;
                }
                else
                {
                    // Cleanup array of SPS and PPS
                    int i = 0;

                    for (i = 0; i < MAX_SPS; i++)
                    {
                        dc->sps_array[i] = NULL;
                    }

                    for (i = 0; i < MAX_PPS; i++)
                    {
                        dc->pps_array[i] = NULL;
                    }

                    dc->active_sei = NULL;

                    dc->active_slice = NULL;

                    dc->mb_array = NULL;

                    TRACE_1(H264, "* DecodingContext allocation success\n");
                }
            }
        }
    }

    // Return the DecodingContext
    return dc;
}
예제 #12
0
파일: ps.cpp 프로젝트: emericg/MiniVideo
int ps_fileParse(MediaFile_t *media)
{
    int retcode = SUCCESS;

    TRACE_INFO(MPS, BLD_GREEN "ps_fileParse()" CLR_RESET);

    // Init bitstream to parse container infos
    Bitstream_t *bitstr = init_bitstream(media, NULL);

    if (bitstr != NULL)
    {
        // Init an MpegPs structure
        MpegPs_t mpg;
        memset(&mpg, 0, sizeof(MpegPs_t));

        // A convenient way to stop the parser
        mpg.run = true;

        // stuff
        const int64_t min_packet_size = 4;

        // Loop on PES packets
        while (mpg.run == true &&
               retcode == SUCCESS &&
               bitstream_get_absolute_byte_offset(bitstr) < (media->file_size - min_packet_size))
        {
            // Init
            PackHeader_t pack_header;
            memset(&pack_header, 0, sizeof(PackHeader_t));
            SystemHeader_t system_header;
            memset(&system_header, 0, sizeof(SystemHeader_t));

            PesHeader_t pes_header;
            memset(&pes_header, 0, sizeof(PesHeader_t));
            PesPacket_t pes_packet;
            memset(&pes_packet, 0, sizeof(PesPacket_t));
            ProgramStreamMap_t pes_streammap;
            memset(&pes_streammap, 0, sizeof(ProgramStreamMap_t));
            ProgramStreamDirectory_t pes_streamdirectory;
            memset(&pes_streamdirectory, 0, sizeof(ProgramStreamDirectory_t));

            // Parse packet header
            parse_pes_header(bitstr, &pes_header);

            switch (pes_header.stream_id)
            {
            case SID_PACK_HEADER:
                retcode = parse_pack_header(bitstr, &pes_header, &pack_header);
                mpg.stat_packheader++;
                break;
            case SID_SYSTEM_HEADER:
                retcode = parse_system_header(bitstr, &pes_header, &system_header);
                mpg.stat_systemheader++;
                break;

            case SID_PROGRAM_STREAM_MAP:
                retcode = parse_program_stream_map(bitstr, &pes_header, &pes_streammap);
                mpg.stat_packet_psm++;
                break;
            case SID_PROGRAM_STREAM_DIRECTORY:
                retcode = parse_program_stream_directory(bitstr, &pes_header, &pes_streamdirectory);
                mpg.stat_packet_psd++;
                break;
            case SID_PRIVATE_STREAM_2:
                TRACE_2(MPS, BLD_GREEN "Private Stream 2 PES" CLR_RESET " @ %lli", pes_header.offset_start);
                mpg.stat_packet_private++;
                break;
            case SID_PADDING:
                retcode = parse_pes_padding(bitstr, &pes_header, &pes_packet);
                mpg.stat_packet_other++;
                break;

            case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6:
            case 0xC7: case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC:
            case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xD2:
            case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: case 0xD8:
            case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE:
            case 0xDF: case SID_PRIVATE_STREAM_1: case SID_AUDIO:
            {
                TRACE_INFO(MPS, BLD_GREEN "parse_pes_audio()" CLR_RESET " @ %lli", pes_header.offset_start);

                // Find a trackid
                unsigned track_id = pes_header.stream_id - 0xC0;
                if (pes_header.stream_id == SID_PRIVATE_STREAM_1)
                    track_id = 0;

                // If a private stream is in the stream, the 'regular' trackid order is shifted
                //while (media->tracks_audio[track_id] == NULL)
                //    track_id--;

                // Init bitstream_map (as needed) to store samples
                if (media->tracks_audio[track_id] == NULL)
                {
                    retcode = init_bitstream_map(&media->tracks_audio[track_id], 0, 999999);
                    media->tracks_audio_count++;
                    media->tracks_audio[track_id]->stream_type = stream_AUDIO;
                }

                retcode = parse_pes(bitstr, &pes_header, &pes_packet);
                parse_pes_a(bitstr, &pes_header, &pes_packet, media->tracks_audio[track_id]);
                mpg.stat_packet_audio++;

                // Set sample into the bitstream_map
                unsigned sample_id = media->tracks_audio[track_id]->sample_count++;
                if (sample_id < 999999)
                {
                    media->tracks_audio[track_id]->sample_type[sample_id] = sample_AUDIO;
                    media->tracks_audio[track_id]->sample_size[sample_id] = pes_header.payload_length - pes_packet.PES_header_data_length;
                    media->tracks_audio[track_id]->sample_offset[sample_id] = pes_header.offset_start + 6 + pes_packet.PES_header_data_length;
                    media->tracks_audio[track_id]->sample_pts[sample_id] = pes_packet.PTS;
                    media->tracks_audio[track_id]->sample_dts[sample_id] = pes_packet.DTS;
                }
            }
            break;

            case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5:
            case 0xE6: case 0xE7: case 0xE8: case 0xE9: case 0xEA:
            case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF:
            case SID_VIDEO:
            {
                TRACE_INFO(MPS, BLD_GREEN "parse_pes_video()" CLR_RESET " @ %lli", pes_header.offset_start + 6);

                // Init bitstream_map (as needed) to store samples
                unsigned track_id = pes_header.stream_id - 0xE0;
                if (media->tracks_video[track_id] == NULL)
                {
                    retcode = init_bitstream_map(&media->tracks_video[track_id], 0, 999999);
                    media->tracks_video_count++;
                    media->tracks_video[track_id]->stream_type = stream_VIDEO;
                }

                retcode = parse_pes(bitstr, &pes_header, &pes_packet);
                parse_pes_v(bitstr, &pes_header, &pes_packet, media->tracks_video[track_id]);
                mpg.stat_packet_video++;

                // Set sample into the bitstream_map
                unsigned sample_id = media->tracks_video[track_id]->sample_count++;
                if (sample_id < 999999)
                {
                    media->tracks_video[track_id]->sample_type[sample_id] = sample_VIDEO;
                    media->tracks_video[track_id]->sample_size[sample_id] = pes_header.payload_length - pes_packet.PES_header_data_length;
                    media->tracks_video[track_id]->sample_offset[sample_id] = pes_header.offset_start + 6 + pes_packet.PES_header_data_length;
                    media->tracks_video[track_id]->sample_pts[sample_id] = pes_packet.PTS;
                    media->tracks_video[track_id]->sample_dts[sample_id] = pes_packet.DTS;
                }
            }
            break;

            case SID_PROGRAM_END:
                mpg.stat_packet_other++;
                mpg.run = false;
                break;

            default:
                TRACE_WARNING(MPS, "Unknown PES packet type (0x%02X) @ %lli",
                              pes_header.stream_id, pes_header.offset_start);
                mpg.stat_packet_other++;
                break;
            }

            retcode = jumpy_pes(bitstr, &pes_header);
        }

        // Free bitstream
        free_bitstream(&bitstr);

        // Recap
        TRACE_INFO(MPS, "MPEG PS (version %u) stats", mpg.mpeg_version);
        TRACE_INFO(MPS, "- Pack Headers:    %u", mpg.stat_packheader);
        TRACE_INFO(MPS, "- System Headers:  %u", mpg.stat_systemheader);
        TRACE_INFO(MPS, "- PSM packets:     %u", mpg.stat_packet_psm);
        TRACE_INFO(MPS, "- PSD packets:     %u", mpg.stat_packet_psd);
        TRACE_INFO(MPS, "- Private packets: %u", mpg.stat_packet_private);
        TRACE_INFO(MPS, "- Audio packets:   %u", mpg.stat_packet_audio);
        TRACE_INFO(MPS, "- Video packets:   %u", mpg.stat_packet_video);
        TRACE_INFO(MPS, "- Unknown packets: %u", mpg.stat_packet_other);
    }
    else
    {
        retcode = FAILURE;
    }

    return retcode;
}
예제 #13
0
int main(int argc, char* argv[])
{
  FILE *fd;
	fd = fopen("predictor_error.txt", "w+");

  FILE *fd1,*fd2;
  fd1 = fopen("predictor1_error.txt", "w+");
  fd2 = fopen("predictor2_error.txt", "w+");


	parameters params;
	codingvars vars;


  image_data* pre_im_data = NULL;//n-1 frame image
  image_data* im_data = NULL;//n frame image

	// parsing command line parameters and/or JPEG-LS header
	params = coding_parameters(argc, argv);

		// encoding process
    //loading previous image data

  pre_im_data = load_image(params.input_file0);
  printf("%s**\n", params.input_file0);
	// loading image data
	im_data = load_image(params.input_file);
  printf("%s**\n", params.input_file);

	// bitstream initialization
	init_bitstream(params.output_file, 'w');
	params.MAXVAL = im_data->maxval;
	write_header(params, im_data);



	// setting parameters
	if(params.specified_T == false)
	{
		/* C.2.4.1.1 Default threshold values */
		if(params.MAXVAL>=128)
		{
			vars.FACTOR = floor((float64)(min(params.MAXVAL,4095)+128)/256);
			params.T1 = CLAMP(vars.FACTOR*(vars.BASIC_T1-2)+2+3*params.NEAR,params.NEAR+1,params.MAXVAL);
			params.T2 = CLAMP(vars.FACTOR*(vars.BASIC_T2-3)+3+5*params.NEAR,params.T1,params.MAXVAL);
			params.T3 = CLAMP(vars.FACTOR*(vars.BASIC_T3-4)+4+7*params.NEAR,params.T2,params.MAXVAL);
		}
		else
		{
			vars.FACTOR = floor( 256.0/(params.MAXVAL + 1) );
			params.T1 = CLAMP(max(2,floor((float64)vars.BASIC_T1/vars.FACTOR)+3*params.NEAR),params.NEAR+1,params.MAXVAL);
			params.T2 = CLAMP(max(2,floor((float64)vars.BASIC_T2/vars.FACTOR)+5*params.NEAR),params.T1,params.MAXVAL);
			params.T3 = CLAMP(max(2,floor((float64)vars.BASIC_T3/vars.FACTOR)+7*params.NEAR),params.T2,params.MAXVAL);
		}
	}
	if(params.verbose)
	{
		fprintf(stdout,	"Encoding %s...\n\n\twidth\t\t%d\n\theight\t\t%d\n\tcomponents\t%d\n",
		params.input_file, im_data->width, im_data->height, im_data->n_comp);
		fprintf(stdout, "\tMAXVAL\t\t%d\n\tNEAR\t\t%d\n\tT1\t\t%d\n\tT2\t\t%d\n\tT3\t\t%d\n\tRESET\t\t%d\n",
		params.MAXVAL, params.NEAR, params.T1, params.T2, params.T3, params.RESET);
	}


	/* A.2 Initializations and conventions */
	init_codingvars(&vars, params);

	//for(vars.comp=0; vars.comp<im_data->n_comp; vars.comp++)
	for(vars.comp=0; vars.comp<1; vars.comp++)
		for(vars.row=0; vars.row<im_data->height; vars.row++)
			for(vars.col=0; vars.col<im_data->width; vars.col++)
			{
				/* A.3 Context determination */
				context_determination(&vars, params, im_data);
        //printf("%s\n", "HERE IT IS!");
        motion_vector(&vars, params, pre_im_data, im_data);
        if((vars.row == 100) && (vars.col >= 200) && (vars.col < 220))
          printf("motion_vector is (%d,%d) and Dif_min is %d.\n", vars.m0,vars.n0,vars.temp);


        prev_context(&vars, params, pre_im_data);
				// regular mode
				/* A.4 Prediction*/
				predict_sample_value(&vars, params);

        predictor1(&vars, params);
        predictor2(&vars, params);

        encode_prediction_error(&vars, params, im_data);
        fprintf(fd, "%d\n", vars.Errval_temp3);

        encode_prediction_error_intra(&vars, params);
        fprintf(fd1, "%d\n", vars.Errval_temp1);
        fprintf(fd2, "%d\n", vars.Errval_temp2);

					/* A.6 Update variables */
					update_codingvars(&vars, params);
			}

	end_bitstream();

	if(params.decoding_flag == true)
		write_image("lena_decoded.ppm", im_data);
	else
		print_bpp(im_data);

	return 0;
}
예제 #14
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_info(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
	debug("Read PIC Info\n");

	// We only get here after seeing that start code
	if (next_u32(esstream) != 0x00010000) // LSB first (0x00000100)
		fatal(CCX_COMMON_EXIT_BUG_BUG, "In read_pic_info: next_u32(esstream) != 0x00010000. Please file a bug report in GitHub.\n");

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

	pic_header(ctx, esstream);
	pic_coding_ext(ctx, esstream);

	if (esstream->error)
		return 0;

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

	// A new anchor frame - flush buffered caption data. Might be flushed
	// in GOP header already.
	if (ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME || ctx->picture_coding_type==CCX_FRAME_TYPE_P_FRAME)
	{
		if (((ctx->picture_structure != 0x1) && (ctx->picture_structure != 0x2)) ||
				(ctx->temporal_reference != ctx->timing->current_tref))
		{
			// NOTE: process_hdcc() needs to be called before set_fts() as it
			// uses fts_now to re-create the timeline !!!!!
			if (ctx->has_ccdata_buffered)
			{
				process_hdcc(ctx, sub);
			}
			anchor_hdcc(ctx, ctx->temporal_reference);
		}
	}

	ctx->timing->current_tref = ctx->temporal_reference;
	ctx->timing->current_picture_coding_type = ctx->picture_coding_type;

	// We mostly use PTS, but when the GOP mode is enabled do not set
	// the FTS time here.
	if (ccx_options.use_gop_as_pts!=1)
	{
		set_fts(ctx->timing); // Initialize fts
	}

	dbg_print(CCX_DMT_VIDES, "  t:%d r:%d p:%d", ctx->top_field_first,
			ctx->repeat_first_field, ctx->progressive_frame);
	dbg_print(CCX_DMT_VIDES, "  FTS: %s\n", print_mstime_static(get_fts(ctx->timing, ctx->current_field)));

	// Set min_pts/sync_pts according to the current time stamp.
	// Use fts_at_gop_start as reference when a GOP header was seen
	// since the last frame 0. If not this is most probably a
	// TS without GOP headers but with USER DATA after each picture
	// header. Use the current FTS values as reference.
	// Note: If a GOP header was present the reference time is from
	// the beginning of the GOP, otherwise it is now.
	if(ctx->temporal_reference == 0)
	{
		ctx->last_gop_length = ctx->maxtref + 1;
		ctx->maxtref = ctx->temporal_reference;

		// frames_since_ref_time is used in set_fts()

		if( ctx->saw_gop_header )
		{
			// This time (fts_at_gop_start) that was set in the
			// GOP header and it might be off by one GOP. See the comment there.
			frames_since_ref_time = ctx->frames_since_last_gop; // Should this be 0?
		}
		else
		{
			// No GOP header, use the current values
			fts_at_gop_start = get_fts(ctx->timing, ctx->current_field);
			frames_since_ref_time = 0;
		}

		if (ccx_options.debug_mask & CCX_DMT_TIME)
		{
			dbg_print(CCX_DMT_TIME, "\nNew temporal reference:\n");
			print_debug_timing(ctx->timing);
		}

		ctx->saw_gop_header = 0; // Reset the value
	}

	if ( !ctx->saw_gop_header && ctx->picture_coding_type==CCX_FRAME_TYPE_I_FRAME )
	{
		// A new GOP beginns with an I-frame. Lets hope there are
		// never more than one per GOP
		ctx->frames_since_last_gop = 0;
	}

	// Set maxtref
	if( ctx->temporal_reference > ctx->maxtref ) {
		ctx->maxtref = ctx->temporal_reference;
		if (ctx->maxtref + 1 > ctx->max_gop_length)
			ctx->max_gop_length = ctx->maxtref + 1;
	}

	unsigned extraframe = 0;
	if (ctx->repeat_first_field)
	{
		ctx->pulldownfields++;
		ctx->total_pulldownfields++;
		if ( ctx->current_progressive_sequence || !(ctx->total_pulldownfields%2) )
			extraframe = 1;
		if ( ctx->current_progressive_sequence && ctx->top_field_first )
			extraframe = 2;
		dbg_print(CCX_DMT_VIDES, "Pulldown: total pd fields: %d - %d extra frames\n",
				ctx->total_pulldownfields, extraframe);
	}

	ctx->total_pulldownframes += extraframe;
	total_frames_count += 1+extraframe;
	ctx->frames_since_last_gop += 1+extraframe;
	frames_since_ref_time += 1+extraframe;

	debug("Read PIC Info - processed\n\n");

	return 1;
}
예제 #15
0
파일: mp3.cpp 프로젝트: emericg/MiniVideo
int mp3_fileParse(MediaFile_t *media)
{
    int retcode = SUCCESS;

    TRACE_INFO(MP3, BLD_GREEN "mp3_fileParse()" CLR_RESET);

    // Init bitstream to parse container infos
    Bitstream_t *bitstr = init_bitstream(media, NULL);

    if (bitstr != NULL)
    {
        // Init a MediaStream_t to store samples
        retcode = init_bitstream_map(&media->tracks_audio[0], 0, 999999);

        // Init an MP3 structure
        mp3_t mp3;
        memset(&mp3, 0, sizeof(mp3_t));

        // A convenient way to stop the parser
        mp3.run = true;

        // stuff
        int64_t min_frame_size = 128;
        int64_t frame_offset = 0;
        uint32_t frame_header = 0;
        bool first_frame_parsed = false;

        // Loop on 1st level elements
        while (mp3.run == true &&
               retcode == SUCCESS &&
               bitstream_get_absolute_byte_offset(bitstr) < (media->file_size - min_frame_size))
        {
            // Seek to the next frame offset // Assume the MP3 frames will not be bigger than 4Gib
            uint32_t jump_bits = (uint32_t)(frame_offset - bitstream_get_absolute_byte_offset(bitstr)) * 8;
            if (jump_bits > 0)
                skip_bits(bitstr, jump_bits);

            // Read the next frame header
            frame_header = read_bits(bitstr, 32);

            // note: check frame header against 11 bits long instead of 12, to be compatible with MPEG-1/2/2.5
            if ((frame_header & 0xFFE00000) == 0xFFE00000)
            {
                TRACE_1(MP3, "> MP3 frame @ %lli", frame_offset);

                if (first_frame_parsed == false)
                {
                    frame_offset = parse_frame_full(bitstr, frame_header, &mp3, media);

                    if (frame_offset > 0)
                        first_frame_parsed = true;
                    else
                        retcode = FAILURE;
                }
                else
                {
                    frame_offset = parse_frame(bitstr, frame_header, &mp3, media);
                }
            }
            else if ((frame_header & 0xFFFFFF00) == 0x54414700)
            {
                TRACE_INFO(MP3, "> ID3v1 tag @ %lli", frame_offset);
                mp3.run = false;

                // Add the TAG to the track
                int sid = media->tracks_audio[0]->sample_count;
                if (sid < 999999)
                {
                    media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG;
                    media->tracks_audio[0]->sample_size[sid] = media->file_size - frame_offset;
                    media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                    media->tracks_audio[0]->sample_pts[sid] = 0;
                    media->tracks_audio[0]->sample_dts[sid] = 0;
                    media->tracks_audio[0]->sample_count++;
                }
            }
            else if ((frame_header & 0xFFFFFF00) == 0x49443300)
            {
                int id3tag_version = ((frame_header & 0x000000FF) << 8) + read_bits(bitstr, 8);
                /*int id3tag_flag =*/ read_bits(bitstr, 8);

                TRACE_INFO(MP3, "> ID3v2.%i @ %lli", id3tag_version, frame_offset);

                uint32_t id3tag_size = read_bits(bitstr, 8) & 0x0000007F;
                id3tag_size <<= 7;
                id3tag_size += read_bits(bitstr, 8) & 0x0000007F;
                id3tag_size <<= 7;
                id3tag_size += read_bits(bitstr, 8) & 0x0000007F;
                id3tag_size <<= 7;
                id3tag_size += read_bits(bitstr, 8) & 0x0000007F;
                id3tag_size += 10; // bytes already read

                // Add the TAG to the track
                int sid = media->tracks_audio[0]->sample_count;
                if (sid < 999999)
                {
                    media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG;
                    media->tracks_audio[0]->sample_size[sid] = id3tag_size;
                    media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                    media->tracks_audio[0]->sample_pts[sid] = 0;
                    media->tracks_audio[0]->sample_dts[sid] = 0;
                    media->tracks_audio[0]->sample_count++;
                }

                // Simulate TAG parsing
                frame_offset += id3tag_size;
            }
            else if (frame_header == 0x4C595249)
            {
                TRACE_INFO(MP3, "> Lyrics3 tag @ %lli", frame_offset);
                frame_offset += 32; // just restart MP3 frame detection 32 bytes later...

                // Add the TAG to the track
                int sid = media->tracks_audio[0]->sample_count;
                if (sid < 999999)
                {
                    media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG;
                    media->tracks_audio[0]->sample_size[sid] = 0;
                    media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                    media->tracks_audio[0]->sample_pts[sid] = 0;
                    media->tracks_audio[0]->sample_dts[sid] = 0;
                    media->tracks_audio[0]->sample_count++;
                }
            }
            else if (frame_header == 0x58696E67)
            {
                TRACE_INFO(MP3, "> XING tag @ %lli", frame_offset);
                frame_offset += 32; // just restart MP3 frame detection 32 bytes later...

                // Add the TAG to the track
                int sid = media->tracks_audio[0]->sample_count;
                if (sid < 999999)
                {
                    media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG;
                    media->tracks_audio[0]->sample_size[sid] = 0;
                    media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                    media->tracks_audio[0]->sample_pts[sid] = 0;
                    media->tracks_audio[0]->sample_dts[sid] = 0;
                    media->tracks_audio[0]->sample_count++;
                }
            }
            else if (frame_header == 0x56425249)
            {
                TRACE_INFO(MP3, "> VBRI tag @ %lli", frame_offset);
                frame_offset += 32; // just restart MP3 frame detection 32 bytes later...

                // Add the TAG to the track
                int sid = media->tracks_audio[0]->sample_count;
                if (sid < 999999)
                {
                    media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG;
                    media->tracks_audio[0]->sample_size[sid] = 0;
                    media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                    media->tracks_audio[0]->sample_pts[sid] = 0;
                    media->tracks_audio[0]->sample_dts[sid] = 0;
                    media->tracks_audio[0]->sample_count++;
                }
            }
            else if (frame_header == 0x41504554)
            {
                TRACE_WARNING(MP3, "> APE tag @ %lli", frame_offset);

                /*uint32_t apetag_header =*/ read_bits(bitstr, 32); // 0x41474558, second part of the tag header
                /*uint32_t apetag_version =*/ read_bits(bitstr, 32);
                uint32_t apetag_size = 8 + read_bits(bitstr, 32); //  APE header size (8 bytes) + tag content size

                // Add the TAG to the track
                int sid = media->tracks_audio[0]->sample_count;
                if (sid < 999999)
                {
                    media->tracks_audio[0]->sample_type[sid] = sample_AUDIO_TAG;
                    media->tracks_audio[0]->sample_size[sid] = apetag_size;
                    media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                    media->tracks_audio[0]->sample_pts[sid] = 0;
                    media->tracks_audio[0]->sample_dts[sid] = 0;
                    media->tracks_audio[0]->sample_count++;
                }

                // Simulate TAG parsing
                frame_offset = frame_offset + apetag_size;
            }
            else
            {
                // Try to find a new startcode closeby...
                frame_offset += 1;
                TRACE_3(MP3, "Unknown frame header @ %lli (startcode: 0x%X)",
                        frame_offset, frame_header);
            }
        }

        if (retcode == SUCCESS)
        {
            retcode = mp3_indexer_track(media, &mp3);
            if (retcode == SUCCESS)
            {
                retcode = mp3_indexer(media, &mp3);
            }
        }
    }
    else
    {
        retcode = FAILURE;
    }

    return retcode;
}