Esempio n. 1
0
    def test_create_script_tag(self):
        s = tags.create_script_tag('onMetaData', {'silly': True})

        self.assertEquals(
            s, ('\x12\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00' +
                '\x02\x00\x0aonMetaData\x08\x00\x00\x00\x01' +
                '\x00\x05silly\x01\x01\x00\x00\x09' + '\x00\x00\x00\x29'))
Esempio n. 2
0
    def test_create_script_tag(self):
        s = tags.create_script_tag('onMetaData', {'silly': True})

        self.assertEquals(s, ('\x12\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00' +
                              '\x02\x00\x0aonMetaData\x08\x00\x00\x00\x01' +
                              '\x00\x05silly\x01\x01\x00\x00\x09' +
                              '\x00\x00\x00\x29'))
Esempio n. 3
0
    def test_create_script_tag(self):
        s = tags.create_script_tag("onMetaData", {"silly": True})

        self.assertEquals(
            s,
            (
                "\x12\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00"
                + "\x02\x00\x0aonMetaData\x08\x00\x00\x00\x01"
                + "\x00\x05silly\x01\x01\x00\x00\x09"
                + "\x00\x00\x00\x29"
            ),
        )
    def onMetaData(self, data):
        self.debug("Meta-data: %r, %s", data, type(data))
        self._component.clear_sizes()

        if not data:
            self.debug("We have been asked to clear metadata, we will do "
                       "it as soon as we get new metadata")
            return

        if not self._published:
            self._internalError('Meta-data received for an unpublished stream')
            return

        if self._started and self._metadata is None:
            # Metadata received too late
            self.debug("Dropping late meta-data")
            return

        if self._creationdate is None:
            self._creationdate = data.get("creationdate", None)
        # Force the creation date to the first one seen,
        # to be able to compare metadata.
        if self._creationdate:
            data["creationdate"] = self._creationdate

        if self._metadata and self._metadata != data:
            self.debug("RTMP stream meta-data changed.")
            self._clear()

        if self._metadata is None:
            self._metadata = data

        self._component.got_metadata(data.copy())

        # a framerate of 1000 sounds unlikely, but seems to happen a lot
        # when ffmpeg streams an .flv file.  Adjust it.
        if self._metadata and self._metadata.get('framerate', None) == 1000:
            self.warning(
                'Client claims framerate is 1000 fps.  Adjusting to 25 fps.')
            self._metadata['framerate'] = 25

        if self._started:
            self.debug("Dropping unchanged meta-data tag")
        else:
            bin = tags.create_script_tag('onMetaData', self._metadata)
            self._addHeader(bin)
            self._tryStarting()
Esempio n. 5
0
def filepositions_difference(metadata, original_metadata_size):
    test_payload = create_script_tag('onMetaData', metadata)
    payload_size = len(test_payload)
    difference = payload_size - original_metadata_size
    return test_payload, difference
Esempio n. 6
0
    metadata['duration'] = duration
    metadata['keyframes'] = keyframes
    metadata['metadatacreator'] = 'flvlib %s' % __versionstr__

    # we're going to write new metadata, so we need to shift the
    # filepositions by the amount of bytes that we're going to add to
    # the metadata tag
    test_payload, difference = filepositions_difference(metadata,
                                                        original_metadata_size)

    if difference:
        new_filepositions = [pos + difference
                             for pos in keyframes.filepositions]
        metadata['keyframes'].filepositions = new_filepositions
        payload = create_script_tag('onMetaData', metadata)
    else:
        log.debug("The file `%s' metadata size did not change.", inpath)
        payload = test_payload

    if outpath:
        try:
            fo = open(outpath, 'wb')
        except IOError, (errno, strerror):
            log.error("Failed to open `%s': %s", outpath, strerror)
            return False
    else:
        try:
            fd, temppath = tempfile.mkstemp()
            # preserve the permission bits
            shutil.copymode(inpath, temppath)
Esempio n. 7
0
def index_file(inpath, outpath=None):
    out_text = (outpath and ("into file `%s'" % outpath)) or "and overwriting"
    log.debug("Indexing file `%s' %s", inpath, out_text)

    try:
        f = open(inpath, 'rb')
    except IOError as e5:
        (errno, strerror) = e5.args
        log.error("Failed to open `%s': %s", inpath, strerror)
        return False

    flv = IndexingFLV(f)
    tag_iterator = flv.iter_tags()
    last_tag = None

    try:
        while True:
            tag = next(tag_iterator)
            # some buggy software, like gstreamer's flvmux, puts a metadata tag
            # at the end of the file with timestamp 0, and we don't want to
            # base our duration computation on that
            if tag.timestamp != 0:
                last_tag = tag
    except MalformedFLV as e:
        message = e.args[0] % e.args[1:]
        log.error("The file `%s' is not a valid FLV file: %s", inpath, message)
        return False
    except EndOfFile:
        log.error("Unexpected end of file on file `%s'", inpath)
        return False
    except StopIteration:
        pass

    if not flv.first_media_tag_offset:
        log.error("The file `%s' does not have any media content", inpath)
        return False

    if not last_tag:
        log.error(
            "The file `%s' does not have any content with a "
            "non-zero timestamp", inpath)
        return False

    metadata = flv.metadata or {}

    if flv.metadata_tag_start:
        original_metadata_size = flv.metadata_tag_end - flv.metadata_tag_start
    else:
        log.debug("The file `%s' has no metadata", inpath)
        original_metadata_size = 0

    keyframes = flv.keyframes

    if flv.no_video:
        log.info("The file `%s' has no video, using audio seekpoints info",
                 inpath)
        keyframes = flv.audio_seekpoints

    duration = metadata.get('duration')
    if not duration:
        # A duration of 0 is nonsensical, yet some tools put it like that. In
        # that case (or when there is no such field) update the duration value.
        duration = last_tag.timestamp / 1000.0

    metadata['duration'] = duration
    metadata['keyframes'] = keyframes
    metadata['metadatacreator'] = 'flvlib %s' % __versionstr__

    # we're going to write new metadata, so we need to shift the
    # filepositions by the amount of bytes that we're going to add to
    # the metadata tag
    test_payload, difference = filepositions_difference(
        metadata, original_metadata_size)

    if difference:
        new_filepositions = [
            pos + difference for pos in keyframes.filepositions
        ]
        metadata['keyframes'].filepositions = new_filepositions
        payload = create_script_tag('onMetaData', metadata)
    else:
        log.debug("The file `%s' metadata size did not change.", inpath)
        payload = test_payload

    if outpath:
        try:
            fo = open(outpath, 'wb')
        except IOError as e2:
            (errno, strerror) = e2.args
            log.error("Failed to open `%s': %s", outpath, strerror)
            return False
    else:
        try:
            fd, temppath = tempfile.mkstemp()
            # preserve the permission bits
            shutil.copymode(inpath, temppath)
            fo = os.fdopen(fd, 'wb')
        except EnvironmentError as e3:
            (errno, strerror) = e3.args
            log.error("Failed to create temporary file: %s", strerror)
            return False

    log.debug("Creating the output file")

    try:
        fo.write(
            create_flv_header(has_audio=flv.has_audio,
                              has_video=flv.has_video))
        fo.write(payload)
        f.seek(flv.first_media_tag_offset)
        shutil.copyfileobj(f, fo)
    except IOError as e6:
        (errno, strerror) = e6.args
        log.error("Failed to create the indexed file: %s", strerror)
        if not outpath:
            # remove the temporary file
            force_remove(temppath)
        return False

    f.close()
    fo.close()

    if not outpath:
        # If we were not writing directly to the output file
        # we need to overwrite the original
        try:
            shutil.move(temppath, inpath)
        except EnvironmentError as e4:
            (errno, strerror) = e4.args
            log.error(
                "Failed to overwrite the original file "
                "with the indexed version: %s", strerror)
            return False

    return True
Esempio n. 8
0
def filepositions_difference(metadata, original_metadata_size):
    test_payload = create_script_tag('onMetaData', metadata)
    payload_size = len(test_payload)
    difference = payload_size - original_metadata_size
    return test_payload, difference
Esempio n. 9
0
    metadata['duration'] = duration
    metadata['keyframes'] = keyframes
    metadata['metadatacreator'] = 'flvlib %s' % __versionstr__

    # we're going to write new metadata, so we need to shift the
    # filepositions by the amount of bytes that we're going to add to
    # the metadata tag
    test_payload, difference = filepositions_difference(metadata,
                                                        original_metadata_size)

    if difference:
        new_filepositions = [pos + difference
                             for pos in keyframes.filepositions]
        metadata['keyframes'].filepositions = new_filepositions
        payload = create_script_tag('onMetaData', metadata)
    else:
        log.debug("The file `%s' metadata size did not change.", inpath)
        payload = test_payload

    if outpath:
        try:
            fo = open(outpath, 'wb')
        except IOError, (errno, strerror):
            log.error("Failed to open `%s': %s", outpath, strerror)
            return False
    else:
        try:
            fd, temppath = tempfile.mkstemp()
            # preserve the permission bits
            shutil.copymode(inpath, temppath)
Esempio n. 10
0
def main():
    PY3K = sys.version_info >= (3, 0)

    if PY3K:
        source = sys.stdin.buffer
    else:
        if sys.platform == "win32":
            import os, msvcrt

            msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
        source = sys.stdin

    header = read_bytes(source, 3)

    if header != "FLV":
        print("Not a valid FLV file")
        return
    write(header)

    # Skip rest of FLV header
    write(read_bytes(source, 6))

    i = 0
    while True:
        header = read_bytes(source, 15)
        if len(header) != 15:
            write(header)
            return

        # Packet structure from Wikipedia:
        #
        # Size of previous packet	uint32_be	0	For first packet set to NULL
        # Packet Type	uint8	18	For first packet set to AMF Metadata
        # Payload Size	uint24_be	varies	Size of packet data only
        # Timestamp Lower	uint24_be	0	For first packet set to NULL
        # Timestamp Upper	uint8	0	Extension to create a uint32_be value
        # Stream ID	uint24_be	0	For first stream of same type set to NULL
        # Payload Data	freeform	varies	Data as defined by packet type

        # Get payload size to know how many bytes to read
        high, low = struct.unpack(">BH", header[5:8])
        payload_size = (high << 16) + low

        # Get timestamp to inject into clock sync tag
        low_high = header[8:12]
        combined = low_high[3] + low_high[:3]
        timestamp = struct.unpack(">i", combined)[0]

        if i % 3:
            data = astypes.FLVObject()
            data["streamClock"] = int(timestamp)
            data["streamClockBase"] = 0
            data["wallClock"] = time.time() * 1000

            # Inject clock sync packet
            write(primitives.make_ui32(payload_size + 15))
            write(tags.create_script_tag("onClockSync", data, timestamp))

            # Write rest of original packet minus previous packet size
            write(header[4:])
            write(read_bytes(source, payload_size))
        else:
            # Write normal packet
            write(header)
            write(read_bytes(source, payload_size))

        i += 1
Esempio n. 11
0
def index_file(inpath, outpath=None):
    out_text = (outpath and ("into file `%s'" % outpath)) or "and overwriting"
    log.debug("Indexing file `%s' %s", inpath, out_text)

    try:
        f = open(inpath, 'rb')
    except IOError as e5:
        (errno, strerror) = e5.args
        log.error("Failed to open `%s': %s", inpath, strerror)
        return False

    flv = IndexingFLV(f)
    tag_iterator = flv.iter_tags()
    last_tag = None

    try:
        while True:
            tag = next(tag_iterator)
            # some buggy software, like gstreamer's flvmux, puts a metadata tag
            # at the end of the file with timestamp 0, and we don't want to
            # base our duration computation on that
            if tag.timestamp != 0:
                last_tag = tag
    except MalformedFLV as e:
        message = e.args[0] % e.args[1:]
        log.error("The file `%s' is not a valid FLV file: %s", inpath, message)
        return False
    except EndOfFile:
        log.error("Unexpected end of file on file `%s'", inpath)
        return False
    except StopIteration:
        pass

    if not flv.first_media_tag_offset:
        log.error("The file `%s' does not have any media content", inpath)
        return False

    if not last_tag:
        log.error("The file `%s' does not have any content with a "
                  "non-zero timestamp", inpath)
        return False

    metadata = flv.metadata or {}

    if flv.metadata_tag_start:
        original_metadata_size = flv.metadata_tag_end - flv.metadata_tag_start
    else:
        log.debug("The file `%s' has no metadata", inpath)
        original_metadata_size = 0

    keyframes = flv.keyframes

    if flv.no_video:
        log.info("The file `%s' has no video, using audio seekpoints info",
                 inpath)
        keyframes = flv.audio_seekpoints

    duration = metadata.get('duration')
    if not duration:
        # A duration of 0 is nonsensical, yet some tools put it like that. In
        # that case (or when there is no such field) update the duration value.
        duration = last_tag.timestamp / 1000.0

    metadata['duration'] = duration
    metadata['keyframes'] = keyframes
    metadata['metadatacreator'] = 'flvlib %s' % __versionstr__

    # we're going to write new metadata, so we need to shift the
    # filepositions by the amount of bytes that we're going to add to
    # the metadata tag
    test_payload, difference = filepositions_difference(metadata,
                                                        original_metadata_size)

    if difference:
        new_filepositions = [pos + difference
                             for pos in keyframes.filepositions]
        metadata['keyframes'].filepositions = new_filepositions
        payload = create_script_tag('onMetaData', metadata)
    else:
        log.debug("The file `%s' metadata size did not change.", inpath)
        payload = test_payload

    if outpath:
        try:
            fo = open(outpath, 'wb')
        except IOError as e2:
            (errno, strerror) = e2.args
            log.error("Failed to open `%s': %s", outpath, strerror)
            return False
    else:
        try:
            fd, temppath = tempfile.mkstemp()
            # preserve the permission bits
            shutil.copymode(inpath, temppath)
            fo = os.fdopen(fd, 'wb')
        except EnvironmentError as e3:
            (errno, strerror) = e3.args
            log.error("Failed to create temporary file: %s", strerror)
            return False

    log.debug("Creating the output file")

    try:
        fo.write(create_flv_header(has_audio=flv.has_audio,
                                   has_video=flv.has_video))
        fo.write(payload)
        f.seek(flv.first_media_tag_offset)
        shutil.copyfileobj(f, fo)
    except IOError as e6:
        (errno, strerror) = e6.args
        log.error("Failed to create the indexed file: %s", strerror)
        if not outpath:
            # remove the temporary file
            force_remove(temppath)
        return False

    f.close()
    fo.close()

    if not outpath:
        # If we were not writing directly to the output file
        # we need to overwrite the original
        try:
            shutil.move(temppath, inpath)
        except EnvironmentError as e4:
            (errno, strerror) = e4.args
            log.error("Failed to overwrite the original file "
                      "with the indexed version: %s", strerror)
            return False

    return True