Ejemplo n.º 1
0
/*!
 * \brief Parse PES packet.
 * \param *bitstr: The bitstream to use.
 * \param *header: A pointer to a PES header structure.
 * \param *packet: A pointer to a PES packet structure.
 * \return 1 if succeed, 0 otherwise.
 *
 * From 'ISO/IEC 13818-1' specification:
 * 2.4.3.6 PES packet.
 * Table 2-17 – PES packet.
 *
 * Parse both MPEG-1 (ISO/IEC 11172-1) and MPEG-2 (ISO/IEC 13818-1) PES packets.
 */
int parse_pes(Bitstream_t *bitstr, PesHeader_t *header, PesPacket_t *packet)
{
    TRACE_2(MPS, "> parse_pes()");
    int retcode = SUCCESS;

    TRACE_INFO(MPS, "parse_pes() 0x%X @ %lli",
               header->start_code, bitstream_get_absolute_byte_offset(bitstr));

    // "regular" PES packet?
    if ((header->stream_id != SID_PROGRAM_STREAM_MAP) &&
        (header->stream_id != SID_PADDING) &&
        (header->stream_id != SID_PRIVATE_STREAM_2) &&
        (header->stream_id != SID_ECM_STREAM) &&
        (header->stream_id != SID_EMM_STREAM) &&
        (header->stream_id != SID_PROGRAM_STREAM_DIRECTORY) &&
        (header->stream_id != SID_DSMCC_STREAM) &&
        (header->stream_id != SID_2221E))
    {
        unsigned checkversion = next_bits(bitstr, 2);

        // Parse MPEG-2 PES header
        if ((checkversion & 0x02) == 0x02)
        {
            packet->mpeg_version = 2;

            if (read_bits(bitstr, 2) != 2)
            {
                TRACE_ERROR(MPS, "wrong 'marker_bits'");
                return FAILURE;
            }

            packet->PES_scrambling_control = read_bits(bitstr, 2);
            packet->PES_priority = read_bit(bitstr);
            packet->data_alignment_indicator = read_bit(bitstr);
            packet->copyright = read_bit(bitstr);
            packet->original_or_copy = read_bit(bitstr);
            packet->PTS_DTS_flag = read_bits(bitstr, 2);
            packet->ESCR_flag = read_bit(bitstr);
            packet->ES_rate_flag = read_bit(bitstr);
            packet->DSM_trick_mode_flag = read_bit(bitstr);
            packet->additional_copy_info_flag = read_bit(bitstr);
            packet->PES_CRC_flag = read_bit(bitstr);
            packet->PES_extension_flag = read_bit(bitstr);
            packet->PES_header_data_length = read_bits(bitstr, 8);

            if (packet->PTS_DTS_flag == 2)
            {
                if (read_bits(bitstr, 4) != 2)
                {
                    TRACE_ERROR(MPS, "wrong 'marker_bit'");
                    return FAILURE;
                }
                packet->PTS = read_bits(bitstr, 3) << 30;
                MARKER_BIT
                packet->PTS += read_bits(bitstr, 15) << 15;
                MARKER_BIT
                packet->PTS += read_bits(bitstr, 15);
                MARKER_BIT
            }
            else if (packet->PTS_DTS_flag == 3)
Ejemplo n.º 2
0
/*!
 * \brief Jumpy protect your parsing - PES edition.
 * \param bitstr: Our bitstream reader.
 * \param header: A pointer to a PES header structure.
 * \return SUCCESS or FAILURE if the jump could not be done.
 *
 * 'Jumpy' is in charge of checking your position into the stream after your
 * parser finish parsing a box / list / chunk / element, never leaving you
 * stranded  in the middle of nowhere with no easy way to get back on track.
 * It will check available informations to known if the current element has been
 * fully parsed, and if not perform a jump (or even a rewind) to the next known
 * element.
 */
int jumpy_pes(Bitstream_t *bitstr, PesHeader_t *header)
{
    int retcode = SUCCESS;

    // Done as a precaution, because the parsing of some boxes (like ESDS...)
    // can leave us in the middle of a byte and that will never be caught by
    // offset checks (cause they works on the assumption that we are byte aligned)
    bitstream_force_alignment(bitstr);

    // Check if we need a jump
    int64_t current_pos = bitstream_get_absolute_byte_offset(bitstr);
    if (current_pos != header->offset_end)
    {
        int64_t file_size = bitstream_get_full_size(bitstr);

        // If the offset_end is past the last byte of the file, we do not need to jump
        // The parser will pick that fact and finish up...
        if (header->offset_end >= file_size)
        {
            bitstr->bitstream_offset = file_size;
            return SUCCESS;
        }

        // Now, do we need to go forward or backward to reach our goal?
        // Then, can we move in our current buffer or do we need to reload a new one?
        if (current_pos < header->offset_end)
        {
            int64_t jump = header->offset_end - current_pos;

            if (jump < (UINT_MAX/8))
                retcode = skip_bits(bitstr, (unsigned int)(jump*8));
            else
                retcode = bitstream_goto_offset(bitstr, header->offset_end);
        }
        else
        {
            int64_t rewind = current_pos - header->offset_end;

            if (rewind > 0)
            {
                if (rewind > (UINT_MAX/8))
                    retcode = rewind_bits(bitstr, (unsigned int)(rewind*8));
                else
                    retcode = bitstream_goto_offset(bitstr, header->offset_end);
            }
        }
    }

    return retcode;
}
Ejemplo n.º 3
0
/*!
 * \brief Parse PES packet header, common to all PES packet types.
 * \param *bitstr: The bitstream to use.
 * \param *header: A pointer to a PES header structure.
 * \return 1 if succeed, 0 otherwise.
 *
 * From 'ISO/IEC 13818-1' specification:
 * 2.4.3.6 PES packet.
 * Table 2-17 – PES packet.
 */
int parse_pes_header(Bitstream_t *bitstr, PesHeader_t *header)
{
    TRACE_2(MPS, "> parse_pes_header()");

    header->offset_start    = bitstream_get_absolute_byte_offset(bitstr);

    header->start_code      = read_bits(bitstr, 32);
    header->stream_id       = header->start_code & 0x000000FF;
    header->payload_length  = read_bits(bitstr, 16);
    header->packet_length   = header->payload_length + 6;

    header->offset_end      = header->offset_start + header->packet_length;

    return SUCCESS;
}
Ejemplo n.º 4
0
/*!
 * \brief parse_ebml_element
 * \note 'bitstr' pointer is not checked for performance reasons.
 *
 * https://matroska.org/technical/specs/index.html
 * https://matroska.org/technical/specs/rfc/index.html
 */
int parse_ebml_element(Bitstream_t *bitstr, EbmlElement_t *element)
{
    TRACE_3(MKV, "parse_ebml_element()");
    int retcode = SUCCESS;

    if (element == NULL)
    {
        TRACE_ERROR(MKV, "Invalid EbmlElement_t structure!");
        retcode = FAILURE;
    }
    else
    {
        // Set element offset
        element->offset_start = bitstream_get_absolute_byte_offset(bitstr);

        // Read element ID
        {
            uint32_t ebml_leadingZeroBits = 0;
            uint32_t ebml_size = 0;

            while (read_bit(bitstr) == 0 && ebml_leadingZeroBits < 4)
                ebml_leadingZeroBits++;

            ebml_size = (ebml_leadingZeroBits + 1) * 7;
            element->eid_size = (ebml_size + ebml_leadingZeroBits + 1) / 8;
            element->eid = read_bits_64(bitstr, ebml_size) + pow(2, ebml_size);
        }

        // Read element size
        {
            uint32_t ebml_leadingZeroBits = 0;
            uint32_t ebml_size = 0;

            while (read_bit(bitstr) == 0 && ebml_leadingZeroBits < 8)
                ebml_leadingZeroBits++;

            ebml_size = (ebml_leadingZeroBits + 1) * 7;
            element->size_size = (ebml_size + ebml_leadingZeroBits + 1) / 8;
            element->size = read_bits_64(bitstr, ebml_size);
        }

        // Set end offset
        element->offset_end = element->offset_start + (element->eid_size + element->size_size + element->size);
    }

    return retcode;
}
Ejemplo n.º 5
0
/*!
 * \brief Parse a program stream map structure.
 * \param *bitstr A bitstream.
 * \param *packet A program stream map structure.
 * \return retcode 1 if succeed, 0 otherwise.
 *
 * \todo Parse desciptors.
 *
 * H.222 / 2.5.4 Program Stream map.
 */
int parse_program_stream_map(Bitstream_t *bitstr, ProgramStreamMap_t *packet)
{
    TRACE_INFO(MPS, BLD_GREEN "parse_program_stream_map()" CLR_RESET " @ %i\n", bitstream_get_absolute_byte_offset(bitstr) - 4);
    int retcode = SUCCESS;
    int i = 0, N = 0, N1 = 0, N2 = 0;

    packet->packet_start_code_prefix = 0x000001;
    packet->map_stream_id = 0xBC;

    packet->program_stream_map_length = read_bits(bitstr, 16);
    packet->current_next_indicator = read_bit(bitstr);
    int reserved1 = read_bits(bitstr, 2);
    packet->program_stream_map_version = read_bits(bitstr, 5);
    int reserved2 = read_bits(bitstr, 7);
    MARKER_BIT
    packet->program_stream_map_info_length = read_bits(bitstr, 16);
    for (i = 0; i < N1; i++)
    {
        // descriptor()
    }

    packet->elementary_stream_map_length = read_bits(bitstr, 16);
    for (i = 0; i < N1; i++)
    {
        // Stack it?
        packet->stream_type = read_bits(bitstr, 8);
        packet->elementary_stream_id = read_bits(bitstr, 8);
        packet->elementary_stream_info_length = read_bits(bitstr, 16);
        for (i = 0; i < N2; i++)
        {
            // descriptor()
        }
    }

    packet->CRC_32 = read_bits(bitstr, 32);

    return retcode;
}
Ejemplo n.º 6
0
/*!
 * \brief Parse a pack header structure.
 * \param *bitstr The bitstream to use.
 * \param *pack_header A pointer to a pack_header structure.
 * \param *system_header A pointer to a system_header 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'.
 */
static int parse_pack_header(Bitstream_t *bitstr, PackHeader_t *pack_header, SystemHeader_t *system_header)
{
    TRACE_INFO(MPS, BLD_GREEN "parse_pack_header()" CLR_RESET " @ %i\n", bitstream_get_absolute_byte_offset(bitstr) - 4);
    int retcode = SUCCESS;
    int i = 0;

    pack_header->pack_start_code = PES_PACK_HEADER;

    if (read_bits(bitstr, 2) != 1)
    {
        TRACE_ERROR(MPS, "wrong 'marker_bit'\n");
        return FAILURE;
    }

    pack_header->system_clock_reference_base = read_bits(bitstr, 3) << 30;
    MARKER_BIT
    pack_header->system_clock_reference_base += read_bits(bitstr, 15) << 15;
    MARKER_BIT
    pack_header->system_clock_reference_base += read_bits(bitstr, 15);
    MARKER_BIT
    pack_header->system_clock_reference_extension = read_bits(bitstr, 9);
    MARKER_BIT
    pack_header->program_mux_rate = read_bits(bitstr, 22);
    MARKER_BIT
    MARKER_BIT
    int reserved = read_bits(bitstr, 5);

    pack_header->pack_stuffing_length = read_bits(bitstr, 3);

    // Stuffing
    for (i = 0; i < pack_header->pack_stuffing_length; i++)
    {
        if (read_bits(bitstr, 8) != 0xFF)
        {
            TRACE_ERROR(MPS, "Wrong 'stuffing_byte'\n");
            return FAILURE;
        }
    }

    // System header
    if (next_bits(bitstr, 32) == PES_SYSTEM_HEADER)
    {
        TRACE_INFO(MPS, BLD_GREEN "parse_system_header()" CLR_RESET " @ %i\n", bitstream_get_absolute_byte_offset(bitstr) - 4);
        skip_bits(bitstr, 32);

        system_header->header_length = read_bits(bitstr, 16);
        MARKER_BIT
        system_header->rate_bound = read_bits(bitstr, 22);
        MARKER_BIT
        system_header->audio_bound = read_bits(bitstr, 6);
        system_header->fixed_flag = read_bits(bitstr, 1);
        system_header->CSPS_flag = read_bits(bitstr, 1);
        system_header->system_audio_lock_flag = read_bits(bitstr, 1);
        system_header->system_video_lock_flag = read_bits(bitstr, 1);
        MARKER_BIT
        system_header->video_bound = read_bits(bitstr, 5);
        system_header->packet_rate_restriction_flag = read_bits(bitstr, 1);

        int reserved_bits = read_bits(bitstr, 7);

        // stack it?
        while (next_bit(bitstr) == 1)
        {
            system_header->stream_id = read_bits(bitstr, 8);
            MARKER_BIT
            MARKER_BIT
            system_header->PSTD_buffer_bound_scale = read_bits(bitstr, 1);
            system_header->PSTD_buffer_size_bound = read_bits(bitstr, 13);
        }
    }
    else
    {
        TRACE_2(MPS, " > No system_header()\n");
    }

    return retcode;
}
Ejemplo n.º 7
0
/*!
 * \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;
}
Ejemplo n.º 8
0
/*!
 * \brief Parse a program stream directory structure.
 * \param *bitstr A bitstream.
 * \param *packet A program stream directory structure.
 * \return retcode 1 if succeed, 0 otherwise.
 *
 * H.222 / 2.5.5 Program Stream directory.
 */
static int parse_program_stream_directory(Bitstream_t *bitstr, ProgramStreamDirectory_t *packet)
{
    TRACE_INFO(MPS, BLD_GREEN "parse_program_stream_directory()" CLR_RESET " @ %i\n", bitstream_get_absolute_byte_offset(bitstr) - 4);
    int retcode = SUCCESS;
    int i = 0;

    packet->packet_start_code_prefix = 0x000001;
    packet->directory_stream_id = 0xFF;
    packet->PES_packet_length = read_bits(bitstr, 16);
    packet->number_of_access_units = read_bits(bitstr, 15);
    MARKER_BIT

    packet->prev_directory_offset = read_bits(bitstr, 15) << 30;
    MARKER_BIT
    packet->prev_directory_offset += read_bits(bitstr, 15) << 15;
    MARKER_BIT
    packet->prev_directory_offset += read_bits(bitstr, 15);
    MARKER_BIT

    packet->next_directory_offset = read_bits(bitstr, 15) << 30;
    MARKER_BIT
    packet->next_directory_offset += read_bits(bitstr, 15) << 15;
    MARKER_BIT
    packet->next_directory_offset += read_bits(bitstr, 15);
    MARKER_BIT

    for (i = 0; i < packet->number_of_access_units; i++)
    {
        // TODO stack it?
        packet->packet_stream_id = read_bits(bitstr, 8);
        packet->PES_header_position_offset_sign = read_bit(bitstr);

        packet->PES_header_position_offset = read_bits(bitstr, 14) << 30;
        MARKER_BIT
        packet->PES_header_position_offset += read_bits(bitstr, 15) << 15;
        MARKER_BIT
        packet->PES_header_position_offset += read_bits(bitstr, 15);
        MARKER_BIT

        packet->reference_offset = read_bits(bitstr, 16);
        MARKER_BIT
        int reserved1 = read_bits(bitstr, 3);

        packet->PTS = read_bits(bitstr, 3) << 30;
        MARKER_BIT
        packet->PTS += read_bits(bitstr, 15) << 15;
        MARKER_BIT
        packet->PTS += read_bits(bitstr, 15);
        MARKER_BIT

        packet->byes_to_read = read_bits(bitstr, 15) << 15;
        MARKER_BIT
        packet->byes_to_read += read_bits(bitstr, 8);
        MARKER_BIT

        packet->intra_coded_indicator = read_bit(bitstr);
        packet->coding_parameters_indicator = read_bits(bitstr, 2);
        int reserved2 = read_bits(bitstr, 4);
    }

    return retcode;
}
Ejemplo n.º 9
0
int h264_decode_nalu(DecodingContext_t *dc, const int64_t nalu_offset, const int64_t nalu_size)
{
    TRACE_1(H264, BLD_GREEN "h264_decode_nalu()" CLR_RESET);
    int retcode = FAILURE;

    // Goto correct data offset
    //bitstream_goto_offset(dc->bitstr, nalu_offset);
    buffer_feed_manual(dc->bitstr, nalu_offset, nalu_size);

    // Check header validity
    if (nalu_parse_header(dc->bitstr, dc->active_nalu))
    {
        TRACE_1(H264, "decode: " BLD_GREEN "NALU_TYPE %i (at %lli) " CLR_RESET,
                dc->active_nalu->nal_unit_type,
                bitstream_get_absolute_byte_offset(dc->bitstr));

        // Decode NAL Unit content
        switch (dc->active_nalu->nal_unit_type)
        {
            case NALU_TYPE_SLICE: //////////////////////////////////////
            {
                TRACE_1(H264, "This decoder only support IDR slice decoding!");
            }
            break;

            case NALU_TYPE_IDR: ////////////////////////////////////////
            {
                TRACE_INFO(H264, "> " BLD_GREEN "decodeIDR(%i at %lli)" CLR_RESET,
                           dc->idrCounter, bitstream_get_absolute_byte_offset(dc->bitstr));

                nalu_clean_sample(dc->bitstr);
                dc->IdrPicFlag = true;

                if (decode_slice(dc))
                {
                    retcode = SUCCESS;
                    dc->errorCounter = 0;
                    dc->idrCounter++;
                    dc->frameCounter++;
                }
                else
                    dc->errorCounter++;
            }
            break;

            case NALU_TYPE_AUD: ////////////////////////////////////////
            {
                nalu_clean_sample(dc->bitstr);

                aud_t aud;
                if (decodeAUD(dc->bitstr, &aud))
                {
                    retcode = SUCCESS;
                }
                else
                    dc->errorCounter++;
            }
            break;

            case NALU_TYPE_SEI: ////////////////////////////////////////
            {
                nalu_clean_sample(dc->bitstr);

                if (dc->active_sei != NULL)
                    free(dc->active_sei);

                dc->active_sei = (sei_t*)calloc(1, sizeof(sei_t));
                if (dc->active_sei)
                {
                    if (decodeSEI(dc->bitstr, dc->active_sei))
                    {
                        retcode = SUCCESS;
                        printSEI(NULL);
                    }
                    else
                        dc->errorCounter++;
                }
            }
            break;

            case NALU_TYPE_SPS: ////////////////////////////////////////
            {
                nalu_clean_sample(dc->bitstr);

                retcode = decodeSPS_legacy(dc);
/*
                sps_t *sps = (sps_t*)calloc(1, sizeof(sps_t));
                if (sps)
                {
                    if (decodeSPS(dc->bitstr, sps))
                    {
                        dc->sps_array[sps->seq_parameter_set_id] = sps;

                        dc->active_sps = sps->seq_parameter_set_id;
                        dc->profile_idc = sps->profile_idc;
                        dc->ChromaArrayType = sps->ChromaArrayType;

                        // Init some quantization tables
                        computeLevelScale4x4(dc, sps);
                        computeLevelScale8x8(dc, sps);

                        // Macroblocks "table" allocation (on macroblock **mbs_data):
                        dc->PicSizeInMbs = sps->FrameHeightInMbs * sps->PicWidthInMbs;
                        dc->mb_array = (Macroblock_t**)calloc(dc->PicSizeInMbs, sizeof(Macroblock_t*));

                        //printSPS(sps);
                        retcode = SUCCESS;
                    }
                    else
                        dc->errorCounter++;
                }
*/
            }
            break;

            case NALU_TYPE_PPS: ////////////////////////////////////////
            {
                nalu_clean_sample(dc->bitstr);

                pps_t *pps = (pps_t*)calloc(1, sizeof(pps_t));
                if (pps)
                {
                    if (decodePPS(dc->bitstr, pps, dc->sps_array))
                    {
                        dc->pps_array[pps->pic_parameter_set_id] = pps;
                        dc->active_pps = pps->pic_parameter_set_id;
                        dc->entropy_coding_mode_flag = pps->entropy_coding_mode_flag,

                        //printPPS(pps, dc->sps_array);
                        retcode = SUCCESS;
                    }
                    else
                        dc->errorCounter++;
                }
            }
            break;

            default:
            {
                TRACE_ERROR(NALU, "Unsupported NAL Unit! (nal_unit_type %i)", dc->active_nalu->nal_unit_type);
                dc->errorCounter++;
            }
            break;
        }

        // Reset NAL Unit structure
        nalu_reset(dc->active_nalu);
    }
    else
    {
        retcode = FAILURE;
        dc->errorCounter++;
        TRACE_WARNING(NALU, "No valid NAL Unit to decode! (errorCounter = %i)", dc->errorCounter);
    }

    return retcode;
}
Ejemplo n.º 10
0
/*!
 * \brief Parse a pack header structure.
 * \param *bitstr The bitstream to use.
 * \param *pack_header A pointer to a pack_header structure.
 * \return 1 if succeed, 0 otherwise.
 *
 * From 'ISO/IEC 13818-1' specification:
 * 2.5.3.3 Pack layer of Program Stream.
 * Table 2-33 – Program Stream pack header
 */
static int parse_pack_header(Bitstream_t *bitstr, PesHeader_t *header, PackHeader_t *packet)
{
    TRACE_INFO(MPS, BLD_GREEN "parse_pack_header()" CLR_RESET " @ %lli",
               header->offset_start);

    int retcode = SUCCESS;

    // Pack Headers do not have lengh field, rewind 2 bytes
    rewind_bits(bitstr, 16);

    if (read_bits(bitstr, 2) != 1)
    {
        TRACE_ERROR(MPS, "wrong 'marker_bits'");
        return FAILURE;
    }

    packet->system_clock_reference_base = read_bits(bitstr, 3) << 30;
    MARKER_BIT
    packet->system_clock_reference_base += read_bits(bitstr, 15) << 15;
    MARKER_BIT
    packet->system_clock_reference_base += read_bits(bitstr, 15);
    MARKER_BIT
    packet->system_clock_reference_extension = read_bits(bitstr, 9);
    MARKER_BIT
    packet->program_mux_rate = read_bits(bitstr, 22);
    MARKER_BIT
    MARKER_BIT
    /*unsigned reserved =*/ read_bits(bitstr, 5);

    packet->pack_stuffing_length = read_bits(bitstr, 3);

    // Stuffing
    for (uint8_t i = 0; i < packet->pack_stuffing_length; i++)
    {
        if (read_bits(bitstr, 8) != 0xFF)
        {
            TRACE_ERROR(MPS, "Wrong 'stuffing_byte'");
            return FAILURE;
        }
    }

    // System header // TODO split into its own function?
    if (next_bits(bitstr, 32) == 0x000001BB)
    {
        TRACE_INFO(MPS, BLD_GREEN "parse_system_header()" CLR_RESET " @ %lli",
                   bitstream_get_absolute_byte_offset(bitstr) - 4);
        skip_bits(bitstr, 48); // start code + size

        SystemHeader_t system_header;

        MARKER_BIT
        system_header.rate_bound = read_bits(bitstr, 22);
        MARKER_BIT
        system_header.audio_bound = read_bits(bitstr, 6);
        system_header.fixed_flag = read_bits(bitstr, 1);
        system_header.CSPS_flag = read_bits(bitstr, 1);
        system_header.system_audio_lock_flag = read_bits(bitstr, 1);
        system_header.system_video_lock_flag = read_bits(bitstr, 1);
        MARKER_BIT
        system_header.video_bound = read_bits(bitstr, 5);
        system_header.packet_rate_restriction_flag = read_bits(bitstr, 1);

        /*unsigned reserved_bits =*/ read_bits(bitstr, 7);

        // stack it?
        while (next_bit(bitstr) == 1)
        {
            system_header.stream_id = read_bits(bitstr, 8);
            MARKER_BIT
            MARKER_BIT
            system_header.PSTD_buffer_bound_scale = read_bits(bitstr, 1);
            system_header.PSTD_buffer_size_bound = read_bits(bitstr, 13);
        }
    }
    else
    {
        TRACE_2(MPS, " > No system_header()");
    }

    // Pack header have no length field, so we just have to parse them correctly
    header->offset_end = bitstream_get_absolute_byte_offset(bitstr);
    header->payload_length = header->offset_end - header->offset_start - 4;

    return retcode;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
/*!
 * \brief Jumpy protect your parsing - MKV edition.
 * \param bitstr: Our bitstream reader.
 * \param parent: The element containing the current element we're in.
 * \param current: The current element we're in.
 * \return SUCCESS or FAILURE if the jump could not be done.
 *
 * 'Jumpy' is in charge of checking your position into the stream after your
 * parser finish parsing a box / list / chunk / element, never leaving you
 * stranded  in the middle of nowhere with no easy way to get back on track.
 * It will check available informations to known if the current element has been
 * fully parsed, and if not perform a jump (or even a rewind) to the next known
 * element.
 */
int jumpy_mkv(Bitstream_t *bitstr, EbmlElement_t *parent, EbmlElement_t *current)
{
    int retcode = SUCCESS;

    // Done as a precaution, because the parsing of some boxes (like ESDS...)
    // can leave us in the middle of a byte and that will never be caught by
    // offset checks (cause they works on the assumption that we are byte aligned)
    bitstream_force_alignment(bitstr);

    // Check if we need a jump
    int64_t current_pos = bitstream_get_absolute_byte_offset(bitstr);
    if (current_pos != current->offset_end)
    {
        int64_t file_size = bitstream_get_full_size(bitstr);
        int64_t offset_end = current->offset_end;

        // Check offset_end
        if (parent && parent->offset_end < file_size) // current element has valid parent
        {
            // Validate offset_end against parent's (parent win)
            if (offset_end > parent->offset_end)
                offset_end = parent->offset_end;
        }
        else // current element has no parent (or parent with invalid offset_end)
        {
            // Validate offset_end against file's (file win)
            if (offset_end > file_size)
                offset_end = file_size;
        }

        // If the offset_end is past the last byte of the file, we do not need to jump
        // The parser will pick that fact and finish up...
        if (offset_end >= file_size)
        {
            if (offset_end > file_size)
                TRACE_WARNING(MKV, "JUMPY > going EOF (%lli)", file_size);

            bitstr->bitstream_offset = file_size;
            return SUCCESS;
        }

        //TRACE_WARNING(MKV, "JUMPY > going from %lli to %lli", current_pos, offset_end);
        //TRACE_WARNING(MKV, "JUMPY > FIXME FIXME FIXME");

        return bitstream_goto_offset(bitstr, offset_end); // FIXME

        // Now, do we need to go forward or backward to reach our goal?
        // Then, can we move in our current buffer or do we need to reload a new one?
        if (current_pos < offset_end)
        {
            int64_t jump = offset_end - current_pos;

            if (jump < (UINT_MAX/8))
                retcode = skip_bits(bitstr, (unsigned int)(jump*8));
            else
                retcode = bitstream_goto_offset(bitstr, offset_end);
        }
        else
        {
            int64_t rewind = current_pos - offset_end;

            if (rewind > 0)
            {
                if (rewind > (UINT_MAX/8))
                    retcode = rewind_bits(bitstr, (unsigned int)(rewind*8));
                else
                    retcode = bitstream_goto_offset(bitstr, offset_end);
            }
        }
    }

    return retcode;
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
0
int64_t parse_frame(Bitstream_t *bitstr, uint32_t frame_header, mp3_t *mp3, MediaFile_t *media)
{
    // Frame infos
    int64_t frame_offset = bitstream_get_absolute_byte_offset(bitstr) - 4;
    int64_t next_frame_offset = 0;
    uint32_t frame_size = 0;
    uint32_t frame_pts = (int64_t)(mp3->audio_pts_tick * mp3->sample_count * 1000.0); // (FAST version)

    // Read MP3 frame header content (FAST version)
    uint32_t bitrate_index = (frame_header & 0x0000F000) >> 12;
    uint32_t padding_bit = (frame_header & 0x00000200) >> 9;
    uint32_t frame_bitrate = bitrate_index_table[mp3->mpeg_version - 1][mp3->mpeg_layer - 1][bitrate_index];

    // Bitrate handling
    mp3->audio_bitrate_vbr += frame_bitrate;
    if (mp3->audio_bitrate_cbr != frame_bitrate)
        mp3->audio_vbr = true;

    if (frame_bitrate && mp3->audio_samplingrate)
    {
        frame_size = (uint32_t)((((double)(((double)mp3->mpeg_sampleperframe / 8.0) * (double)frame_bitrate) / (double)(mp3->audio_samplingrate)) * 1000.0) + padding_bit);
        next_frame_offset = frame_offset + frame_size;

        if (frame_size != 0 && next_frame_offset < bitstr->bitstream_size)
        {
            TRACE_2(MP3, "> Valid MPEG-%u Layer %u frame @ %lli, size: %u (bitrate: %u, samplingrate: %u)",
                    mp3->mpeg_version, mp3->mpeg_layer, frame_offset, frame_size, frame_bitrate, mp3->audio_samplingrate);

            // Set MP3 frame into the bitstream_map
            int sid = media->tracks_audio[0]->sample_count;
            if (sid < 999999)
            {
                media->tracks_audio[0]->sample_type[sid] = sample_AUDIO;
                media->tracks_audio[0]->sample_size[sid] = frame_size;
                media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                media->tracks_audio[0]->sample_pts[sid] = frame_pts;
                media->tracks_audio[0]->sample_dts[sid] = 0;
                media->tracks_audio[0]->sample_count++;
            }

            // Update total track size
            mp3->sample_size_total += frame_size;
            mp3->sample_count++;

            // Update max sample size
            if (frame_size > mp3->sample_size_max)
            {
                mp3->sample_size_max = frame_size;
            }
        }
        else
        {
            TRACE_WARNING(MP3, "> Invalid MPEG-%u Layer %u frame: out of boundaries @ %lli + size: %u (bitrate: %u, samplingrate: %u)",
                          mp3->mpeg_version, mp3->mpeg_layer, frame_offset, frame_size, frame_bitrate, mp3->audio_samplingrate);

            if ((frame_size > 0) && (frame_size <= 1152))
            {
                // If the MP3 frame size is <= 1152 but out of boundaries, there
                // is a chance that we are at the end of the file anyway, so let's
                // not throw everything away and just stop the parsing here.
                next_frame_offset = bitstr->bitstream_size;
                mp3->run = false;
            }
            else
            {
                next_frame_offset = -1;
            }
        }
    }
    else
    {
        TRACE_WARNING(MP3, "> Invalid MPEG-%u L%u frame: bad bitrate or samplingrate @ %lli + size: %u (bitrate: %u, samplingrate: %u)",
                      mp3->mpeg_version, mp3->mpeg_layer, frame_offset, frame_size, frame_bitrate, mp3->audio_samplingrate);

        // Try "manual parsing", maybe we will find a new startcode closeby...
        next_frame_offset = frame_offset + 1;
    }

    return next_frame_offset;
}
Ejemplo n.º 15
0
int64_t parse_frame_full(Bitstream_t *bitstr, uint32_t frame_header, mp3_t *mp3, MediaFile_t *media)
{
    // Frame infos
    int64_t frame_offset = bitstream_get_absolute_byte_offset(bitstr) - 4;
    int64_t next_frame_offset = 0;
    uint32_t frame_size = 0;
    int64_t frame_pts = 0;
    uint32_t frame_bitrate = 0;

    // Read MP3 frame header content
    uint32_t audio_version_id   = (frame_header & 0x00180000) >> 19;
    uint32_t layer_index        = (frame_header & 0x00060000) >> 17;
    uint32_t protection_bit     = (frame_header & 0x00010000) >> 16;
    uint32_t bitrate_index      = (frame_header & 0x0000F000) >> 12;
    uint32_t samplingrate_index = (frame_header & 0x00000C00) >> 10;
    uint32_t padding_bit        = (frame_header & 0x00000200) >> 9;
    uint32_t private_bit        = (frame_header & 0x00000100) >> 8;
    mp3->audio_channels         = (frame_header & 0x000000C0) >> 6;
    uint32_t mode_extension     = (frame_header & 0x00000030) >> 4;
    uint32_t copyright          = (frame_header & 0x00000080) >> 3;
    uint32_t original           = (frame_header & 0x00000040) >> 2;
    uint32_t emphasis           = (frame_header & 0x00000003);

    switch (audio_version_id)
    {
    case 0x00:
        mp3->mpeg_version = 3; // MPEG-2.5
        break;

    case 0x01:
    case 0x02:
        mp3->mpeg_version = 2; // MPEG-2
        break;

    case 0x03:
        mp3->mpeg_version = 1; // MPEG-1
        break;
    }

    switch (layer_index)
    {
    case 0x03:
        mp3->mpeg_layer = 1; // Layer 1
        break;

    case 0x02:
        mp3->mpeg_layer = 2; // Layer 2
        break;

    default:
    case 0x01:
    case 0x00: // reserved
        mp3->mpeg_layer = 3; // Layer 3
        break;
    }

    if (bitrate_index_table[mp3->mpeg_version - 1][mp3->mpeg_layer - 1][bitrate_index])
    {
        frame_bitrate = bitrate_index_table[mp3->mpeg_version - 1][mp3->mpeg_layer - 1][bitrate_index];

        mp3->audio_bitrate_vbr += frame_bitrate;

        if (mp3->sample_count == 0)
            mp3->audio_bitrate_cbr = frame_bitrate;
        else if (mp3->audio_bitrate_cbr != frame_bitrate)
            mp3->audio_vbr = true;
    }

    if (samplingrate_index_table[mp3->mpeg_version - 1][samplingrate_index])
    {
        mp3->audio_samplingrate = samplingrate_index_table[mp3->mpeg_version - 1][samplingrate_index];
    }

    if (sampleperframe_table[mp3->mpeg_version - 1][mp3->mpeg_layer - 1])
    {
        mp3->mpeg_sampleperframe = sampleperframe_table[mp3->mpeg_version - 1][mp3->mpeg_layer - 1];
    }

    if (frame_bitrate && mp3->audio_samplingrate)
    {
        // Audio frame duration in milliseconds
        if (mp3->mpeg_layer == 1)
        {
            if (mp3->mpeg_version == 1) // MPEG-1 layer 1
            {
                // tick: number of frames * 384 / sampling rate
                mp3->audio_pts_tick = ((double)mp3->mpeg_sampleperframe / (double)mp3->audio_samplingrate) * 1000.0;
            }
            else // MPEG-2/2.5 layer 1
            {
                // tick: number of frames * 132 / sampling rate
                mp3->audio_pts_tick = (132.0 / (double)mp3->audio_samplingrate * 1000.0);
            }
        }
        else // MPEG-1/2/2.5 layer 2/3
        {
            // tick: number of frames * 1152 / sampling rate
            mp3->audio_pts_tick = ((double)mp3->mpeg_sampleperframe / (double)mp3->audio_samplingrate) * 1000.0;
        }

        // Frame PTS (method 1)
        //if (mp3->sample_count > 0)
        //    frame_pts = media->tracks_audio[0]->sample_pts[mp3->sample_count - 1];
        //frame_pts += mp3->audio_pts_tick * 1000.0;

        // Frame PTS (method 2)
        frame_pts = (int64_t)(mp3->audio_pts_tick * mp3->sample_count * 1000.0);

        // Frame size
        frame_size = (uint32_t)((((double)(((double)mp3->mpeg_sampleperframe / 8.0) * (double)frame_bitrate) / (double)(mp3->audio_samplingrate)) * 1000.0) + padding_bit);
        next_frame_offset = frame_offset + frame_size;

        if (frame_size != 0 && next_frame_offset < bitstr->bitstream_size)
        {
            TRACE_2(MP3, "> Valid MPEG-%u Layer %u frame @ %lli, size: %u (bitrate: %u, samplingrate: %u)",
                    mp3->mpeg_version, mp3->mpeg_layer, frame_offset, frame_size, frame_bitrate, mp3->audio_samplingrate);

            // Set MP3 frame into the bitstream_map
            int sid = media->tracks_audio[0]->sample_count;
            if (sid < 999999)
            {
                media->tracks_audio[0]->sample_type[sid] = sample_AUDIO;
                media->tracks_audio[0]->sample_size[sid] = frame_size;
                media->tracks_audio[0]->sample_offset[sid] = frame_offset;
                media->tracks_audio[0]->sample_pts[sid] = frame_pts;
                media->tracks_audio[0]->sample_dts[sid] = 0;
                media->tracks_audio[0]->sample_count++;
            }

            // Update total track size
            mp3->sample_size_total += frame_size;
            mp3->sample_count++;

            // Update max sample size
            if (frame_size > mp3->sample_size_max)
            {
                mp3->sample_size_max = frame_size;
            }
        }
        else
        {
            TRACE_WARNING(MP3, "> Invalid MPEG-%u Layer %u frame: out of boundaries @ %lli + size: %u (bitrate: %u, samplingrate: %u)",
                          mp3->mpeg_version, mp3->mpeg_layer, frame_offset, frame_size, frame_bitrate, mp3->audio_samplingrate);

            if ((frame_size > 0) && (frame_size <= 1152))
            {
                // If the MP3 frame size is <= 1152 but out of boundaries, there
                // is a chance that we are at the end of the file anyway, so let's
                // not throw everything away and just stop the parsing here.
                next_frame_offset = bitstr->bitstream_size;
                mp3->run = false;
            }
            else
            {
                next_frame_offset = -1;
            }
        }
    }
    else
    {
        TRACE_WARNING(MP3, "> Invalid MPEG-%u L%u frame: bad bitrate or samplingrate @ %lli + size: %u (bitrate: %u, samplingrate: %u)",
                      mp3->mpeg_version, mp3->mpeg_layer, frame_offset, frame_size, frame_bitrate, mp3->audio_samplingrate);

        // Try "manual parsing", maybe we will find a new startcode closeby...
        next_frame_offset = frame_offset + 1;
    }

    return next_frame_offset;
}