/* * $Id$ * Copyright (C) 2010 gingko - http://gingko.homeip.net/ * * This file is part of Pouchin TV Mod, a free DVB-T viewer. * See http://www.pouchintv.fr/ for updates. * * Pouchin TV Mod is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Pouchin TV Mod is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * * Most files of this project have been changed from the Pouchin TV * project (Copyright (C) 2006 Pouchin ), * to use with a modified version of this software. * See http://pouchinteve.free.fr/ for the original project. */ /** \file * \brief Gestion d'intervalles mémoire et de flux d'octets et de bits * * Ce fichier définit les classes et méthodes définies pour les structures de * référencement d'intervalles d'adresses mémoire, ainsi que pour la lecture de * flux d'octets et de bits. **/ #pragma once #include "utils.h" // ==================================================================================== enum StreamErrors { serr_NoError, serr_OutOfData, serr_BufferOverflow, serr_TooManyBitsRequestedAtOnce, serr_RewindTooLarge }; // ==================================================================================== /// Définition d'un intervalle mémoire par adresse et longueur template struct PtrRng { const T * ptr; //!< Pointeur sur l'adresse de début UINT siz; //!< Longueur de l'espace pointé /// Constructeur par défaut PtrRng() : ptr(NULL), siz(0) { } /// Construction à partir d'un pointeur et d'une longueur PtrRng(const T * pt, UINT sz) : ptr(pt), siz(sz) { } /// Construction à partir de deux pointeurs PtrRng(const T * ptr1, const T * ptr2) : ptr(ptr1), siz((UINT)(ptr2 - ptr1)) { } /// Constructeur copie PtrRng(const PtrRng & sM) : ptr(sM.ptr), siz(sM.siz) { } /// Retourner l'adresse qui suit celle du dernier octet PCUINT8 end() const { return ptr+siz; } /// Élimination de "sz" octets par le début PtrRng & operator += (UINT sz) { if (sz > siz) sz = siz; ptr += sz; siz -= sz; return *this; } /// Recul de "sz" octets par le début PtrRng & operator -= (UINT sz) { ptr -= sz; siz += sz; return *this; } /// Redéfinir l'adresse de départ dans l'intervalle existant, en ajustant la longueur PtrRng & operator >>= (const T * new_ptr) { new_ptr = min(max(new_ptr, ptr), end()); siz -= UINT(new_ptr - ptr); ptr = new_ptr; return *this; } /// Élimination de "sz" objets "T" par le début PtrRng operator + (UINT sz) const { return PtrRng(*this) += sz; } /// Recul de "sz" objets "T" par le début PtrRng operator - (UINT sz) const { return PtrRng(*this) -= sz; } /// Retourne le premier objet "T" et l'élimine T get() { return siz == 0 ? T() : (--siz, *ptr++); } /// Retourne \p true si l'intervalle courant est entièrement contenu dans l'intervalle \p sM bool isIn(const PtrRng & sM) const { return ptr != NULL && sM.ptr != NULL && ptr >= sM.ptr && end() <= sM.end(); } /// Retourner le début de l'espace mémoire en tant que référence sur un objet de type défini template const T & as() const { return *reinterpret_cast(ptr); } }; // ==================================================================================== typedef PtrRng MemRng; // ==================================================================================== /// Abstraction pour la lecture d'un flux d'octets class ByteStream { protected: virtual UINT8 peek_byte() = 0; virtual UINT8 next_byte() = 0; virtual void unread_bytes(UINT count) = 0; virtual bool end_of_stream() const = 0; public: virtual bool empty() { return end_of_stream();} void fill_bytes_table(PUINT8 tbl, UINT siz) { while (siz > 0) {*tbl++ = next_byte(); --siz;}} void skip_bytes(UINT count) { while (count > 0) {next_byte(); --count; }} }; // ==================================================================================== class BitStream : virtual public ByteStream { void load_byte_in_cache(); public: UINT bit_cache; //!< Cache pour les prochains bits à lire UINT8 bit_cnt; //!< Nombre de bits restant à lire dans le cache BitStream() : bit_cache(0), bit_cnt(0) { } /** * Alignement à l'octet, avec déchargement des bits préchargés si nécessaire ; après appel à cette * fonction, il est garanti que le pointeur 'pcur' pointe le prochain octet à lire **/ void align(); /** * \brief Lecture des \p cnt bits suivants dans le flot * \param[in] cnt Nombre de bits à lire * \return Bits lus, sous forme d'entier non signé * \note La valeur de \p cnt est valide pour le nombre de bits contenus dans un entier moins 7, * soit 25 en compilation 32 bits, et 57 en compilation 64 bits * Cette limite est portée à 32 ou 64 juste après l'appel de la fonction membre \p align. **/ UINT getbits(UINT8 cnt); UINT8 getbit(); bool getflag() { return getbit() != 0; } UINT32 peekbits(UINT8 count); UINT8 peekbit() { UINT8 res = getbit(); ++bit_cnt; return res; } bool peekflag() { return peekbit() != 0; } void rewind_bits(UINT8 count); UINT8 get8bits() { return (UINT8)getbits(8); } UINT16 get16bits() { return (UINT16)getbits(16); } UINT32 get32bits() { #ifdef _WIN64 return (UINT32)getbits(32); #else UINT32 res = getbits(16) << 16; return res |getbits(16); #endif } UINT64 get64bits() { UINT64 res = UINT64(get32bits()) << 32; return res | get32bits(); } /** * Remplissage d'une table de valeurs scalaires avec un nombre définis de valeurs d'une taille * identique compris entre issues d'un flot d'octets **/ template void fill_table(T * tbl, UINT siz, UINT8 cnt) { while (siz > 0) {*tbl++ = T(getbits(cnt)); --siz;} } /** * Lecture d'après une table VLC (Variable Length Code). * Le premier élément de cette table est un mot de 16 bits de la forme 'bbbbdddddddddddd', avec * 'bbbb' = nombre de bits à lire + 7 (donc le bit de poids fort est toujours à 1, constituant * ainsi un déterminant), et 'dddddddddddd' est un offset positif vers une sous-table de * longueur 2^(bbbb-7), dans laquelle on lit une valeur indexée par la valeur retournée par * les (bbbb-7) bits lus. * Chaque élément de cette sous-table est, soit un autre mot de 16 bits analogue * (et on continue à parcourir la table, en extrayant à chaque fois du flux le nombre de bits * indiqués dans cette table), soit du type '0vvvvvvvvvvvvvvv', auquel cas on retourne la * valeur 'vvvvvvvvvvvvvvv'. **/ UINT16 get_vlc_bits(PCUINT16 pvlc); /** * Lecture d'une valeur non signée codée en codage exponentiel-Golomb * \see http://fr.wikipedia.org/wiki/Code_exponentiel-Golomb * \see ISO/IEC 14496-10 section 9.1 **/ UINT get_eg(); /** * Lecture d'une valeur signée codée en codage exponentiel-Golomb * \see ISO/IEC 14496-10 section 9.1.1 **/ INT get_eg_s(); bool empty() { return !bit_cnt && __super::empty();} }; // ==================================================================================== /// Classe de lecture d'un flux de bits placés en mémoire dans des octets adjacents class BitRng : public BitStream, private MemRng { UINT8 nbit; /// Numéro du prochain bit à lire (0 = bit de poids fort, 7 = bit de /// poids faible, 8 = lecture de l'octet suivant nécessaire) virtual bool end_of_stream() const { return siz == 0; } protected: virtual UINT8 peek_byte() { return *ptr; } virtual UINT8 next_byte() { return get(); } virtual void unread_bytes(UINT count) { (*this) -= 1; } public: BitRng(MemRng sM = MemRng()) : MemRng(sM), nbit(0) { } BitRng(const BitRng & sB) : MemRng(sB), nbit(sB.nbit) { } PCUINT8 getptr() { align(); return ptr; } }; // ==================================================================================== /// Classe de lecture d'un flux de bits placés en mémoire dans des octets adjacents, /// et dans lesquels peuvent exister des octets 0x03 de prévention d'émulation (H264) /// \see ISO/IEC 14496-10 section 7.4.1, "emulation_prevention_three_byte" class BitRng_ep3 : public BitRng { UINT8 zerocount; //!< comptage des zéros virtual UINT8 next_byte(); public: BitRng_ep3(MemRng sM = MemRng()) : BitRng(sM), zerocount(0) { } BitRng_ep3(const BitRng_ep3 & sB) : BitRng(sB), zerocount(sB.zerocount) { } }; // ====================================================================================