예제 #1
0
def test_mux_next_packet_error(
        tmpdir,
        fixtures,
        v_store, v_pt, v_enc,
        a_store, a_pt, a_enc,
        fmt,
        count):
    # v
    v_src = fixtures.join(v_store)
    v_pkts = marm.rtp.RTPCursor([v_src.strpath], packet_type=v_pt)
    v_prof = pytest.probe(v_pkts)

    # a
    a_src = fixtures.join(a_store)
    a_pkts = marm.rtp.RTPCursor([a_src.strpath], packet_type=a_pt)
    a_prof = pytest.probe(a_pkts)

    # mux

    class MyException(Exception):

        pass

    local = {'call_count': 0}

    def v_pkts_wrapper():
        for i, v_pkt in enumerate(v_pkts):
            local['call_count'] += 1
            if i > count:
                raise MyException('poop')
            yield v_pkt

    m_path = tmpdir.join('mux.{0}'.format(fmt))
    with pytest.raises(MyException) as ei:
        with m_path.open('wb') as fo:
            marm.frame.mux(
                fo,
                video_profile={
                    'encoder_name': v_enc,
                    'pix_fmt': marm.VideoFrame.PIX_FMT_YUV420P,
                    'width': v_prof['width'],
                    'height': v_prof['height'],
                    'frame_rate': v_prof['frame_rate'],
                    'bit_rate': v_prof['bit_rate'],
                    'time_base': (1, 1000),
                },
                video_packets=marm.VideoFrames(v_pkts_wrapper()),
                audio_profile={
                    'encoder_name': a_enc,
                    'bit_rate': a_prof['bit_rate'],
                    'sample_rate': a_prof['sample_rate'],
                    'channel_layout': a_prof['channel_layout'],
                    'time_base': (1, 1000),
                },
                audio_packets=marm.Frames(a_pkts)
            )
    assert 'poop' in ei.value
    assert local == {'call_count': count + 2}
예제 #2
0
def test_concat_muxed(
        tmpdir,
        fixtures,
        pool,
        ffmpeg,
        v_store, v_enc,
        a_store, a_enc,
        dur,
        fmt):
    # split v
    v_path = fixtures.join(v_store)
    v_parts = 0
    v_pkts = marm.mjr.MJRRTPPacketReader(
        str(v_path),
        packet_type=marm.vp8.VP8RTPPacket
    )
    for i, part in enumerate(marm.rtp.split_packets(v_pkts, duration=dur)):
        t_path = tmpdir.join('v-{0}.mjr'.format(i + 1))
        with t_path.open('wb') as t_fo:
            marm.mjr.write_header(t_fo, 'video')
            for pkt in part:
                marm.mjr.write_packet(t_fo, pkt)
        v_parts += 1

    # split a
    a_path = fixtures.join(a_store)
    a_parts = 0
    a_pkts = marm.mjr.MJRRTPPacketReader(
        str(a_path),
        packet_type=marm.opus.OpusRTPPacket
    )
    for i, part in enumerate(marm.rtp.split_packets(a_pkts, duration=dur)):
        t_path = tmpdir.join('a-{0}.mjr'.format(i + 1))
        with t_path.open('wb') as t_fo:
            marm.mjr.write_header(t_fo, 'audio')
            for pkt in part:
                marm.mjr.write_packet(t_fo, pkt)
        a_parts += 1

    # cursor for split parts
    v_cur = marm.rtp.RTPCursor([
            str(tmpdir.join('v-{0}.mjr'.format(i + 1)))
            for i in range(v_parts)
        ],
        marm.mjr.MJRRTPPacketReader,
        packet_type=marm.vp8.VP8RTPPacket,
    )
    a_cur = marm.rtp.RTPCursor([
            str(tmpdir.join('a-{0}.mjr'.format(i + 1)))
            for i in range(a_parts)
        ],
        marm.mjr.MJRRTPPacketReader,
        packet_type=marm.opus.OpusRTPPacket,
    )

    # probe
    v_prof = pytest.probe(v_cur)
    a_prof = pytest.probe(a_cur)

    # calculate mux points
    mux_points = []
    assert v_parts == a_parts
    for i in range(v_parts):
        # begin
        v_cur.seek((i, 0))
        v_b_drop = 0
        a_cur.seek((i, 0))
        a_b_drop = 0
        a_b_delay = 0
        a_b = a_cur.tell()
        v_pkt = v_cur.current()
        if v_cur.prev_key_frame():
            v_cur.prev()
            v_b = v_cur.tell()
            a_b_delay = int((v_pkt.msecs - v_cur.current().msecs))
            v_b_drop = (
                v_cur.count((i, 0), lambda pkt: pkt.data.is_start_of_frame) - 1
            )
        elif v_pkt.data.is_key_frame:
            v_b = v_cur.tell()
        elif v_cur.next_key_frame():
            v_cur.prev()
            v_b = v_cur.tell()
            a_cur.fastforward(v_pkt.msecs - v_cur.current().msecs)
            a_b = a_cur.tell()
        else:
            assert not (
                'Could not find key-frame in "{0}" part "{1}"'
                .format(v_path, i + 1)
            )

        # end
        v_cur.seek((i, -1))
        v_pkt = v_cur.current()
        if not v_pkt.data.is_start_of_frame:
            if v_cur.prev_start_of_frame() is None:
                assert not (
                    'Could not find prev start-of-frame in "{0}" part "{1}"'
                    .format(v_path, i + 1)
                )
            v_cur.prev()
        v_e = v_cur.tell()
        a_e = (i + 1, 0)

        mux_points.append((v_b, v_b_drop, v_e, a_b, a_b_drop, a_b_delay, a_e))

    # mux parts
    for i, (v_b, _, v_e, a_b, _, a_b_delay, a_e) in enumerate(mux_points):
        # packets
        v_cur.seek(v_b)
        v_pkts = v_cur.slice(v_e)
        a_cur.seek(a_b)
        a_pkts = a_cur.slice(a_e)

        # mux
        p_path = tmpdir.join('mux-{0}.{1}'.format(i + 1, fmt))
        with p_path.open('wb') as fo:
            marm.frame.mux(
                fo,
                video_profile={
                    'encoder_name': v_enc,
                    'pix_fmt': marm.VideoFrame.PIX_FMT_YUV420P,
                    'width': v_prof['width'],
                    'height': v_prof['height'],
                    'frame_rate': v_prof['frame_rate'],
                    'bit_rate': v_prof['bit_rate'],
                    'time_base': (1, 1000),
                },
                video_packets=marm.VideoFrames(v_pkts),
                audio_profile={
                    'encoder_name': a_enc,
                    'bit_rate': a_prof['bit_rate'],
                    'sample_rate': a_prof['sample_rate'],
                    'channel_layout': a_prof['channel_layout'],
                    'time_base': (1, 1000),
                },
                audio_packets=marm.Frames(a_pkts, a_b_delay),
            )

    # xcode parts
    xcodes = []
    for i, point in enumerate(mux_points):
        v_b, v_b_drop, v_e, a_b, a_b_drop, _, a_e = point
        p_path = tmpdir.join('mux-{0}.{1}'.format(i + 1, fmt))
        x_path = tmpdir.join('xcode-{0}.{1}'.format(i + 1, fmt))
        cmd = [
            ffmpeg,
            '-i', p_path,
            '-codec:v', v_enc,
            '-filter:v',
            '"select=gte(n\\, {0}), setpts=PTS-STARTPTS"'.format(v_b_drop),
            '-codec:a', a_enc,
            '-filter:a',
            '"aselect=gte(n\\, {0}), asetpts=PTS-STARTPTS"'.format(a_b_drop),
            x_path,
        ]
        xcodes.append(' '.join(map(str, cmd)))
    for _, ex in pool.imap(check_output, xcodes):
        assert ex is None

    # concat xcoded parts
    c_txt_path = tmpdir.join('concat.txt')
    c_txt_path.write('\n'.join([
        'file {0}'.format(tmpdir.join('xcode-{0}.{1}'.format(i + 1, fmt)))
        for i in range(len(mux_points))
    ]))
    c_path = tmpdir.join('concat.{0}'.format(fmt))
    cmd = [
        ffmpeg,
        '-f', 'concat',
        '-safe', '0',
        '-i', str(c_txt_path),
        '-c', 'copy',
        str(c_path),
    ]
    subprocess.check_call(args=' '.join(cmd), shell=True)