Beispiel #1
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;
}
Beispiel #2
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;
}
Beispiel #3
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;
}