Пример #1
0
    def _parse(self):
        self._trak, self._moov_pos = self._file.trak(self._label)

        stbl = get_sample_table(self._trak)

        co_box = next(find_boxes(stbl.boxes, [b"stco", b"co64"]))
        self._file.seek(self._moov_pos + co_box.header.start_pos +
                        co_box.header.header_size + 4)  # entry_count
        self._co_buffer = self._file.read(co_box.header.box_size -
                                          co_box.header.header_size -
                                          4)  # entry_count

        self._co = np.frombuffer(
            self._co_buffer,
            np.dtype(">u4")
            if co_box.header.type == b"stco" else np.dtype(">u8"))

        sz_box = next(find_boxes(stbl.boxes, [b"stsz"]))
        if sz_box.sample_size > 0:
            self._sz = np.full(co_box.entry_count, sz_box.sample_size,
                               np.uint32)
        else:
            self._file.seek(self._moov_pos + sz_box.header.start_pos +
                            sz_box.header.header_size + 4 +  # sample_size
                            4)  # sample_count
            self._sz_buffer = self._file.read(sz_box.header.box_size -
                                              sz_box.header.header_size -
                                              4 -  # sample_size
                                              4)  # sample_count
            self._sz = np.frombuffer(self._sz_buffer, np.dtype(">u4"))

        self._len = co_box.entry_count
Пример #2
0
    def video_configuration_location(self):
        stsd = next(find_boxes(get_sample_table(self._trak).boxes, [b"stsd"]))
        c1 = next(find_boxes(stsd.boxes, [b"avc1", b"hec1", b"hvc1"]), None)

        if not c1:
            return None

        cC = next(find_boxes(c1.boxes, [b"avcC", b"hvcC"]))
        return (self._moov_pos + cC.header.start_pos + cC.header.header_size,
                cC.header.box_size - cC.header.header_size)
Пример #3
0
def _append_index_bzna_target(filename, moov_filename, mdat_targets_offset):
    moov = _load_moov(moov_filename)
    mvhd = next(find_boxes(moov.boxes, [b"mvhd"]))

    samples_trak = next(find_traks(moov.boxes, [b"bzna_input\0"]))
    # TRAK.MDIA.MINF.STBL
    stbl = samples_trak.boxes[-1].boxes[-1].boxes[-1]
    samples_offsets = next(find_boxes(stbl.boxes, [b"stco", b"co64"]))
    samples_sizes = next(find_boxes(stbl.boxes, [b"stsz"]))

    # bzna_target trak
    if next(find_traks(moov.boxes, [b"bzna_target\0"]), None) is not None:
        trak = next(find_traks(moov.boxes, [b"bzna_target\0"]))
        moov.boxes = [box for box in moov.boxes if box is not trak]

    targets_size = 0
    targets = []
    sizes = []

    with open(filename, "rb") as container_file:
        for offset, size in zip(
            (o.chunk_offset for o in samples_offsets.entries),
            (s.entry_size for s in samples_sizes.samples)):
            container_file.seek(offset)
            sample_bstr = ConstBitStream(container_file.read(size))
            # Create a new tmp object to hold the content
            sample_moov = next(find_boxes(Parser.parse(sample_bstr),
                                          [b"moov"]))
            sample_moov.load(sample_bstr)

            target = get_trak_sample_bytes(sample_bstr, sample_moov.boxes,
                                           b"bzna_target\0", 0)
            # Test subset is reached meaning that remaining entries will
            # not contain a target
            if target is None:
                break

            targets.append(target)
            sizes.append(len(target))
            targets_size += len(target)

    # MOOV.TRAK
    trak = _make_bzna_target_trak(sizes, mdat_targets_offset,
                                  mvhd.next_track_id)
    moov.append(trak)
    mvhd.next_track_id += 1
    moov.refresh_box_size()

    with open(filename, "rb+") as container_file, \
         open(moov_filename, "wb") as moov_file:
        moov_file.write(bytes(moov))
        container_file.seek(mdat_targets_offset)
        container_file.write(b''.join(targets))

    return mdat_targets_offset + targets_size
Пример #4
0
def test_find_headers_at():
    creation_time = utils.to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = utils.to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    samples_sizes = [198297, 127477, 192476]
    samples_offset = 10
    trak = utils.make_trak(creation_time, modification_time,
                           samples_sizes, samples_offset)

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]
    tkhd.track_id = 1
    tkhd.width = [512, 0]
    tkhd.height = [512, 0]

    trak.refresh_box_size()

    buffer = io.BytesIO(bytes(trak))
    for (pos, box_size, box_type, header_size), \
        box in zip(mp4.find_headers_at(buffer, {b'tkhd', b'mdia'},
                                       offset=trak.header.header_size),
                   utils.find_boxes(trak.boxes, {b'tkhd', b'mdia'})):
        assert pos < buffer.tell()
        assert box_size == box.header.box_size
        assert box_type == box.header.type
        if isinstance(box.header, headers.FullBoxHeader):
            assert header_size + 4 == box.header.header_size
        else:
            assert header_size == box.header.header_size
Пример #5
0
def test_find_traks():
    boxes = [
        utils.make_meta_trak(0, 0, b"trak1\0", [], 0),
        utils.make_meta_trak(0, 0, b"trak2\0", [], 0),
        utils.make_meta_trak(0, 0, b"trak3\0", [], 0),
        bx_def.UnknownBox(hd_def.BoxHeader()),
        utils.make_meta_trak(0, 0, b"trak2\0", [], 0)
    ]

    boxes[3].header.type = b"0001"

    assert utils.get_name(next(utils.find_traks(boxes,
                                                b"trak1\0"))) == b"trak1\0"
    assert utils.get_name(next(utils.find_traks(boxes,
                                                b"trak2\0"))) == b"trak2\0"
    assert utils.get_name(next(utils.find_traks(boxes,
                                                b"trak3\0"))) == b"trak3\0"

    assert [
        utils.get_name(trak) for trak in utils.find_traks(boxes, b"trak2\0")
    ] == [b"trak2\0", b"trak2\0"]
    assert [
        utils.get_name(trak)
        for trak in utils.find_traks(boxes, [b"trak1\0", b"trak3\0"])
    ] == [b"trak1\0", b"trak3\0"]

    assert next(utils.find_boxes(boxes, b"0004"), None) is None
Пример #6
0
def _update_mdat_size(filename, mdat_data_end):
    bstr = ConstBitStream(filename=filename)
    mdat = next(find_boxes(Parser.parse(bstr, recursive=False), [b"mdat"]))
    del bstr

    mdat.header.box_ext_size = mdat_data_end - mdat.header.start_pos

    # Update mdat header
    with open(filename, "rb+") as container_file:
        container_file.seek(mdat.header.start_pos)
        container_file.write(bytes(mdat.header))

    return mdat_data_end
Пример #7
0
def _index_bzna_thumb(filename, moov_filename, mdat_data_end):
    moov = _load_moov(moov_filename)
    mvhd = next(find_boxes(moov.boxes, [b"mvhd"]))

    samples_trak = next(find_traks(moov.boxes, [b"bzna_input\0"]))
    # TRAK.MDIA.MINF.STBL
    stbl = samples_trak.boxes[-1].boxes[-1].boxes[-1]
    samples_offsets = next(find_boxes(stbl.boxes, [b"stco", b"co64"]))
    samples_sizes = next(find_boxes(stbl.boxes, [b"stsz"]))

    # bzna_target trak
    if next(find_traks(moov.boxes, [b"bzna_thumb\0"]), None) is not None:
        trak = next(find_traks(moov.boxes, [b"bzna_thumb\0"]))
        moov.boxes = [box for box in moov.boxes if box is not trak]

    hvc1 = None
    offsets = []
    sizes = []

    with open(filename, "rb") as container_file:
        for offset, size in zip(
            (o.chunk_offset for o in samples_offsets.entries),
            (s.entry_size for s in samples_sizes.samples)):
            container_file.seek(offset)
            sample_bstr = ConstBitStream(container_file.read(size))
            # Create a new tmp object to hold the content
            sample_moov = next(find_boxes(Parser.parse(sample_bstr),
                                          [b"moov"]))
            sample_moov.load(sample_bstr)

            # MOOV.TRAK
            trak = next(find_traks(sample_moov.boxes, [b"bzna_thumb\0"]))
            # MOOV.TRAK.MDIA.MINF.STBL
            stbl = trak.boxes[-1].boxes[-1].boxes[-1]
            co = next(find_boxes(stbl.boxes, [b"stco", b"co64"]))
            stsz = next(find_boxes(stbl.boxes, [b"stsz"]))

            if hvc1 is None:
                # MOOV.TRAK.MDIA.MINF.STBL.STSD._VC1
                hvc1 = stbl.boxes[0].boxes[-1]

            offsets.append(offset + co.entries[0].chunk_offset)
            sizes.append(stsz.sample_size)

    # MOOV.TRAK
    trak = _make_bzna_thumb_trak(hvc1, sizes, offsets, mvhd.next_track_id)
    moov.append(trak)
    mvhd.next_track_id += 1
    moov.refresh_box_size()

    with open(moov_filename, "wb") as moov_file:
        moov_file.write(bytes(moov))

    return mdat_data_end
Пример #8
0
def _index_bzna_input(filename, moov_filename, mdat_input_offset):
    moov = _load_moov(moov_filename)
    mvhd = next(find_boxes(moov.boxes, [b"mvhd"]))

    samples_headers = _get_samples_headers(filename, mdat_input_offset)
    samples_headers = jug.value(samples_headers)

    # bzna_input trak
    if next(find_traks(moov.boxes, [b"bzna_input\0"]), None) is not None:
        trak = next(find_traks(moov.boxes, [b"bzna_input\0"]))
        moov.boxes = [box for box in moov.boxes if box is not trak]

    samples_size = 0
    sample_size = -1
    sizes = []

    for sample_header in samples_headers:
        # Every sample starts with a ftyp box
        if sample_header.type == b"ftyp":
            if sample_size >= 0:
                sizes.append(sample_size)
                samples_size += sample_size
            sample_size = 0

        sample_size += sample_header.box_size

    sizes.append(sample_size)
    samples_size += sample_size

    # MOOV.TRAK
    trak = _make_bzna_input_trak(sizes, mdat_input_offset, mvhd.next_track_id)
    moov.append(trak)
    mvhd.next_track_id += 1
    moov.refresh_box_size()

    with open(moov_filename, "wb") as moov_file:
        moov_file.write(bytes(moov))

    return mdat_input_offset + samples_size
Пример #9
0
def test_get_sample_size_at():
    creation_time = utils.to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = utils.to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    samples_sizes = [198297, 127477, 192476]
    samples_offset = 10
    trak = utils.make_trak(creation_time, modification_time,
                           samples_sizes, samples_offset)

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]
    tkhd.track_id = 1
    tkhd.width = [512, 0]
    tkhd.height = [512, 0]

    trak.refresh_box_size()

    buffer = io.BytesIO(bytes(trak))
    stbl_pos, _, _, _ = mp4.find_sample_table_at(buffer, 0)
    sz, _ = mp4.get_sample_size_at(buffer, stbl_pos)
    stbl = utils.get_sample_table(trak)
    stsz = next(utils.find_boxes(stbl.boxes, {b"stsz"}))
    assert (sz == [e.entry_size for e in stsz.samples]).all()
Пример #10
0
def test_find_boxes():
    boxes = [
        bx_def.UnknownBox(hd_def.BoxHeader()),
        bx_def.UnknownBox(hd_def.BoxHeader()),
        bx_def.UnknownBox(hd_def.BoxHeader()),
        bx_def.UnknownBox(hd_def.BoxHeader())
    ]

    boxes[0].header.type = b"0001"
    boxes[1].header.type = b"0002"
    boxes[2].header.type = b"0003"
    boxes[3].header.type = b"0002"

    assert next(utils.find_boxes(boxes, b"0001")).header.type == b"0001"
    assert next(utils.find_boxes(boxes, b"0002")).header.type == b"0002"
    assert next(utils.find_boxes(boxes, b"0003")).header.type == b"0003"

    assert [box.header.type
            for box in utils.find_boxes(boxes, b"0002")] == [b"0002", b"0002"]
    assert [
        box.header.type for box in utils.find_boxes(boxes, [b"0001", b"0003"])
    ] == [b"0001", b"0003"]

    assert next(utils.find_boxes(boxes, b"0004"), None) is None
Пример #11
0
def test_index_metadata():
    try:
        container_filename, transcoded_files = _create_container()

        _run_tasks([index_metadata(container_filename)])

        assert not os.path.exists(container_filename + ".moov")

        bstr = ConstBitStream(filename=container_filename)
        boxes = list(Parser.parse(bstr))

        # mdat should be using the box extended size field to prevent having to
        # shift data if it is bigger than the limit of the regular box size field
        mdat = next(find_boxes(boxes, b"mdat"))
        assert mdat.header.box_ext_size is not None

        moov = next(find_boxes(boxes, b"moov"))
        moov.load(bstr)

        explicit_targets = [
            b'\x00\x00\x00\x00\x00\x00\x00\x00',
            b'\x00\x00\x00\x00\x00\x00\x00\x00',
            b'\x00\x00\x00\x00\x00\x00\x00\x00',
            b'\x00\x00\x00\x00\x00\x00\x00\x00',
            b'\x00\x00\x00\x00\x00\x00\x00\x00',
            b'\x01\x00\x00\x00\x00\x00\x00\x00',
            b'\x01\x00\x00\x00\x00\x00\x00\x00',
            b'\x01\x00\x00\x00\x00\x00\x00\x00',
            b'\x01\x00\x00\x00\x00\x00\x00\x00', None
        ]

        explicit_filenames = [
            b'n01440764_11155.JPEG\x00', b'n01440764_7719.JPEG\x00',
            b'n01440764_7304.JPEG\x00', b'n01440764_8469.JPEG\x00',
            b'n01440764_6432.JPEG\x00', b'n01443537_2772.JPEG\x00',
            b'n01443537_1029.JPEG\x00', b'n01443537_1955.JPEG\x00',
            b'n01443537_962.JPEG\x00', b'n01443537_2563.JPEG\x00'
        ]

        samples = [
            get_trak_sample_bytes(bstr, moov.boxes, b"bzna_input\0", i)
            for i in range(10)
        ]
        targets = [
            get_trak_sample_bytes(bstr, moov.boxes, b"bzna_target\0", i)
            for i in range(10)
        ]
        filenames = [
            get_trak_sample_bytes(bstr, moov.boxes, b"bzna_fname\0", i)
            for i in range(10)
        ]
        thumbs = [
            get_trak_sample_bytes(bstr, moov.boxes, b"bzna_thumb\0", i)
            for i in range(10)
        ]

        for i, (sample, target, filename, thumb, transcoded_file) in \
                enumerate(zip(samples, targets, filenames, thumbs,
                              transcoded_files)):
            sample_bstr = ConstBitStream(bytes=sample)
            sample_moov = next(find_boxes(Parser.parse(sample_bstr), b"moov"))
            sample_moov.load(sample_bstr)
            sample_transcoded_filename = filename.decode("utf-8")[:-1] + \
                                         ".transcoded"
            assert transcoded_file.endswith(sample_transcoded_filename)
            assert hashlib.md5(sample).hexdigest() == \
                   _md5(transcoded_file)
            assert target == explicit_targets[i]
            assert target == get_trak_sample_bytes(sample_bstr,
                                                   sample_moov.boxes,
                                                   b"bzna_target\0", 0)
            assert filename == explicit_filenames[i]
            assert filename == get_trak_sample_bytes(sample_bstr,
                                                     sample_moov.boxes,
                                                     b"bzna_fname\0", 0)
            assert thumb == get_trak_sample_bytes(sample_bstr,
                                                  sample_moov.boxes,
                                                  b"bzna_thumb\0", 0)

    finally:
        shutil.rmtree(".", ignore_errors=True)
Пример #12
0
    def __init__(self, src, ar_format="mp4"):
        super().__init__(src, ar_format)

        bstr = ConstBitStream(filename=self._src)
        moov = next(find_boxes(Parser.parse(bstr, recursive=False), [b"moov"]))
        moov.parse_boxes(bstr, recursive=False)
        for trak in find_boxes(moov.boxes, [b"trak"]):
            trak.parse_boxes(bstr, recursive=False)
            mdia = next(find_boxes(trak.boxes, [b"mdia"]))
            mdia.parse_boxes(bstr, recursive=False)

        trak = next(find_traks(moov.boxes, [b"bzna_input\0"]))
        mdia = next(find_boxes(trak.boxes, [b"mdia"]))
        minf = next(find_boxes(mdia.boxes, [b"minf"]))
        minf.parse_boxes(bstr, recursive=False)
        stbl = next(find_boxes(minf.boxes, [b"stbl"]))
        stbl.parse_boxes(bstr, recursive=False)
        co = next(find_boxes(stbl.boxes, {b"stco", b"co64"}))
        sz = next(find_boxes(stbl.boxes, [b"stsz"]))

        self._input_co = co
        self._input_sz = sz

        trak = next(find_traks(moov.boxes, [b"bzna_fname\0"]))
        mdia = next(find_boxes(trak.boxes, [b"mdia"]))
        minf = next(find_boxes(mdia.boxes, [b"minf"]))
        minf.parse_boxes(bstr, recursive=False)
        stbl = next(find_boxes(minf.boxes, [b"stbl"]))
        stbl.parse_boxes(bstr, recursive=False)
        co = next(find_boxes(stbl.boxes, {b"stco", b"co64"}))
        sz = next(find_boxes(stbl.boxes, [b"stsz"]))

        self._fname_co = co
        self._fname_sz = sz

        self._len = max(self._input_co.entry_count,
                        self._input_sz.sample_count)