Ticket #93: mpeg_duration.patch

File mpeg_duration.patch, 5.2 kB (added by haypo, 2 years ago)

Patch to compute MPEG duration in seconds

  • hachoir-parser/hachoir_parser/video/mpeg_video.py

    old new  
    1212""" 
    1313 
    1414from hachoir_parser import Parser 
    15 from hachoir_core.field import (FieldSet, 
     15from hachoir_core.field import (FieldSet, createOrphanField, 
    1616    FieldError, ParserError, 
    1717    Bit, Bits, Bytes, PaddingBits, NullBits, 
    1818    UInt8, UInt16, 
     
    2121from hachoir_core.endian import BIG_ENDIAN 
    2222from hachoir_core.text_handler import hexadecimal 
    2323 
     24MAX_CHUNK_SIZE = 4096 # bytes 
     25 
    2426class Timestamp(FieldSet): 
    2527    static_size = 36 
    2628 
     
    3941    static_size = 35 
    4042 
    4143    def createFields(self): 
    42         yield Bits(self, "scr_a", 3) 
     44        yield Bits(self, "a", 3) 
    4345        yield Bit(self, "sync[]") # =True 
    44         yield Bits(self, "scr_b", 15) 
     46        yield Bits(self, "b", 15) 
    4547        yield Bit(self, "sync[]") # =True 
    46         yield Bits(self, "scr_c", 15) 
     48        yield Bits(self, "c", 15) 
    4749 
     50    def createValue(self): 
     51        return (((self["a"].value << 15) + self["b"].value) << 15) + self["c"].value 
     52 
    4853class ProgramStream(FieldSet): 
    4954    def createFields(self): 
    5055        if self.stream.readBits(self.absolute_address, 2, self.endian) == 1: 
     
    6469        else: 
    6570            # MPEG version 1 
    6671            yield Bits(self, "sync[]", 4) 
    67             yield Bits(self, "scr_a", 3) 
    68             yield Bit(self, "sync[]") 
    69             yield Bits(self, "scr_b", 15) 
    70             yield Bit(self, "sync[]") 
    71             yield Bits(self, "scr_c", 15) 
     72            yield SCR(self, "scr") 
    7273            yield Bits(self, "sync[]", 2) 
    7374            yield Bits(self, "mux_rate", 22) 
    7475            yield Bit(self, "sync[]") 
     
    8788        elif (sync0.size == 4 and sync0.value == 2): 
    8889            # MPEG1 
    8990            if not self["sync[1]"].value \ 
    90             or not self["sync[2]"].value \ 
    91             or self["sync[3]"].value != 3 \ 
    92             or not self["sync[4]"].value: 
     91            or not self["sync[2]"].value: 
    9392                return "Invalid synchronisation bits" 
    9493        else: 
    9594            return "Unknown version" 
     
    142141 
    143142class Video(FieldSet): 
    144143    def createFields(self): 
     144        yield Bytes(self, "xx", 48-36) 
     145        return 
     146 
    145147        yield Bits(self, "sync[]", 2) # =2 
    146148        if self["sync[0]"].value != 2: 
    147149            raise ParserError("Unknown video elementary data") 
     
    194196        yield Chunk(self, "chunk[]") 
    195197 
    196198class Chunk(FieldSet): 
    197     ISO_END_CODE = 0xB9 
     199    TAG_END = 0xB9 
    198200    tag_info = { 
    199201# SLICE_START_CODE_MIN : 0x01 
    200202# SLICE_START_CODE_MAX : 0xAF 
     
    213215        0xBB: ("system_start[]", None,          "System start"), 
    214216        0xBE: ("padding[]",      Padding,       "Padding"), 
    215217        0xC0: ("audio[]",        None,          "Audio"), 
     218        # FIXME: ID 0xE0..0xEF ? (video id 0..15 ?) 
    216219        0xE0: ("video[]",        Video,         "Video elementary"), 
    217220        0xFF: ("directory[]",    None,          "Program Stream Directory"), 
    218221    } 
     
    222225        tag = self["tag"].value 
    223226        if tag in self.tag_info: 
    224227            self._name, self.parser, self._description = self.tag_info[tag] 
    225             if not self.parser
     228            if not self.parser and (tag != self.TAG_END)
    226229                self.parser = defaultParser 
    227230        else: 
    228231            self.parser = defaultParser 
     
    284287        else: 
    285288            return "MPEG-1 video" 
    286289 
     290    def createLastPackStart(self): 
     291        if not self._size: 
     292            return 
     293        start = self.size - MAX_CHUNK_SIZE*8 
     294        # FIXME: Use reverse search (end to the start) 
     295        # because MAX_CHUNK_SIZE bytes may contains two or more pack start! 
     296        offset = self.stream.searchBytes("\0\0\1\xBA", start) 
     297        if offset is None: 
     298            return None 
     299        return createOrphanField(self, offset, Chunk, "pack_start") 
     300 
  • hachoir-metadata/hachoir_metadata/video.py

    old new  
    11from hachoir_core.field import MissingField 
    22from hachoir_core.error import HachoirError 
    33from hachoir_metadata.metadata import Metadata, MultipleMetadata, registerExtractor 
    4 from hachoir_parser.video import MovFile, AsfFile, FlvFile 
     4from hachoir_parser.video import MovFile, AsfFile, FlvFile, MPEGVideoFile 
    55from hachoir_parser.container import MkvFile 
    66from hachoir_core.i18n import _ 
    77from hachoir_core.tools import makePrintable 
     
    277277#                    meta.compression = text 
    278278        return meta 
    279279 
     280class MpegVideoMetadata(Metadata): 
     281    def extract(self, mpeg): 
     282        self.compression = "MPEG" 
     283        pack = mpeg.createLastPackStart() 
     284        if pack \ 
     285        and "content/scr" in pack \ 
     286        and pack["content/scr"].hasValue(): 
     287            self.duration = pack["content/scr"].value // 90 
     288 
    280289registerExtractor(MovFile, MovMetadata) 
    281290registerExtractor(AsfFile, AsfMetadata) 
    282291registerExtractor(FlvFile, FlvMetadata) 
    283292registerExtractor(MkvFile, MkvMetadata) 
     293registerExtractor(MPEGVideoFile, MpegVideoMetadata) 
    284294