Esempio n. 1
0
def test_get_metadata(video_path, exp_metadata):
    metadata = services.get_metadata(video_path=video_path)

    assert metadata == exp_metadata
    assert sorted(metadata.keys()) == sorted(
        ('audio_stream', 'video_stream', 'summary', 'format')
    )
Esempio n. 2
0
 def make(**kwargs):
     video = video_factory(
         video_path=VIDEO_PATH,
         description='description',
         tags=['tag1', 'tag2'],
         visibility='draft',
         title='title',
         **kwargs,
     )
     file_ = simple_uploaded_file_factory(video_path=VIDEO_PATH)
     models.VideoRendition.objects.create(
         video=video,
         file=file_,
         playlist_file=rendition_playlist_file,
         file_size=1000,
         width=256,
         height=144,
         duration=10,
         ext='webm',
         container='webm',
         audio_codec='opus',
         video_codec='vp9',
         profile='mpeg4_144p',
         name='mpeg4_144p',
         framerate=30,
         metadata=media_services.get_metadata(VIDEO_PATH),
     )
     return video
Esempio n. 3
0
def test_transcode_profile_does_apply(video_filename, profile_cls, exp_result):
    video_path = constants.TEST_DATA_DIR / video_filename
    metadata_summary = services.get_metadata(video_path)['summary']

    result = manager._transcode_profile_does_apply(
        profile_cls=profile_cls, metadata_summary=metadata_summary)

    assert result == exp_result
Esempio n. 4
0
def test_generate_default_thumbnail_image(tmpdir):
    image_path = TEST_DATA_DIR / 'thumbnail-vertical.jpg'
    test_image_path = tmpdir / 'thumbnail-vertical.jpg'
    shutil.copyfile(image_path, test_image_path)

    result_image = services._generate_default_thumbnail_image(
        image_path=test_image_path
    )

    assert result_image.exists()
    metadata = services.get_metadata(result_image)
    assert metadata['summary']['width'] == 1280
    assert metadata['summary']['height'] == 720
Esempio n. 5
0
def video_with_renditions_and_segments(video, simple_uploaded_file, tmpdir):
    video_renditions_to_create = (
        (640, 360, constants.VID_360P_24FPS, False),
        (640, 360, constants.VID_360P_24FPS, True),
        (1920, 1080, constants.VIDEO_PATH_1080_60FPS, True),
    )
    for (
            width,
            height,
            video_path,
            create_segments,
    ) in video_renditions_to_create:
        video_rendition = models.VideoRendition.objects.create(
            video=video,
            file=simple_uploaded_file,
            name=f'mpeg4_{height}p',
            profile=f'mpeg4_{height}p',
            ext='webm',
            framerate=30,
            file_size=1,
            width=width,
            height=height,
            metadata=media_services.get_metadata(video_path),
            codecs_string='avc1.640028,mp4a.40.2',
        )
        assert not video_rendition.playlist_file
        if not create_segments:
            continue
        video_path = constants.VIDEO_PATH_1080_30FPS_VERT
        profile = transcoder_profiles.MpegFour360p
        (
            segments_playlist_file,
            segment_paths,
            _,
        ) = ffmpeg._create_segments_for_video(
            video_path=video_path,
            profile=profile,
            tmp_dir=tmpdir,
            video_rendition_id=video_rendition.id,
            video_id=video_rendition.video_id,
        )
        media_services.persist_video_rendition_segments(
            video_rendition=video_rendition,
            segments_playlist_file=segments_playlist_file,
            segments=segment_paths,
        )
    return video, video_renditions_to_create
def test_ffmpeg_generate_thumbnails(tmpdir):
    video_path = Path(tmpdir / constants.VID_1920_X_960.name)
    shutil.copyfile(constants.VID_1920_X_960, video_path)

    thumbnails = ffmpeg._ffmpeg_generate_thumbnails(
        video_file_path=video_path,
        profile=transcoder_profiles.MpegFour720p,
    )

    assert thumbnails
    for offset, thumb_path in thumbnails:
        assert offset > 0
        assert thumb_path.exists()
        metadata = services.get_metadata(thumb_path)
        # Height is fixed and width is auto.
        assert metadata['summary']['height'] == 720
        assert metadata['summary']['width'] == 1440
def test_create_segments_for_video(tmpdir, video_with_renditions_and_segments):
    video_path = constants.VIDEO_PATH_1080_30FPS_VERT
    profile = transcoder_profiles.Webm360p
    video, _ = video_with_renditions_and_segments
    video_rendition = video.videorendition_set.first()
    video_rendition_id = video_rendition.id
    video_id = video_rendition.video_id

    (
        segments_playlist_file,
        segment_paths,
        codecs_string,
    ) = ffmpeg._create_segments_for_video(
        video_path=video_path,
        profile=profile,
        tmp_dir=tmpdir,
        video_rendition_id=video_rendition_id,
        video_id=video_id,
    )

    exp_num_segments = 13
    assert len(segment_paths) == exp_num_segments
    assert all(p.exists() and isinstance(p, Path) for p in segment_paths)
    assert isinstance(segments_playlist_file, Path)
    assert segments_playlist_file.exists()

    assert codecs_string == 'avc1.640028,mp4a.40.2'

    segment_names_durations = [
        (p.name, services.get_metadata(p)['summary']['duration'])
        for p in segment_paths
    ]
    exp_segment_names_durations = [
        ('0.ts', 9.2092),
        ('1.ts', 3.3033),
        ('2.ts', 4.337667),
        ('3.ts', 7.540867),
        ('4.ts', 4.537867),
        ('5.ts', 4.6046),
        ('6.ts', 6.006),
        ('7.ts', 8.341667),
        ('8.ts', 3.036367),
        ('9.ts', 6.773433),
        ('10.ts', 5.472133),
        ('11.ts', 8.341667),
        ('12.ts', 5.9059),
    ]
    assert segment_names_durations == exp_segment_names_durations
    exp_playlist = f"""
    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:9
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXTINF:9.209200,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/0.ts
    #EXTINF:3.303300,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/1.ts
    #EXTINF:4.337667,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/2.ts
    #EXTINF:7.540867,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/3.ts
    #EXTINF:4.537867,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/4.ts
    #EXTINF:4.604600,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/5.ts
    #EXTINF:6.006000,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/6.ts
    #EXTINF:8.341667,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/7.ts
    #EXTINF:3.036367,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/8.ts
    #EXTINF:6.773433,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/9.ts
    #EXTINF:5.472133,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/10.ts
    #EXTINF:8.341667,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/11.ts
    #EXTINF:5.905900,
    /videos/{video_id}/renditions/{video_rendition_id}/segments/12.ts
    #EXT-X-ENDLIST
    """
    assert (m3u8.load(str(segments_playlist_file)).dumps() == m3u8.loads(
        exp_playlist).dumps())
def test_create_segments_for_video(
    tmpdir, settings, video_with_renditions_and_segments
):
    video_path = constants.VIDEO_PATH_1080_30FPS_VERT
    profile = transcoder_profiles.MpegFour360p
    video, _ = video_with_renditions_and_segments
    video_rendition = video.renditions.first()
    video_rendition_id = video_rendition.id
    video_id = video_rendition.video_id

    (
        segments_playlist_file,
        segment_paths,
        codecs_string,
    ) = ffmpeg._create_segments_for_video(
        video_path=video_path,
        profile=profile,
        tmp_dir=tmpdir,
        video_rendition_id=video_rendition_id,
        video_id=video_id,
    )

    exp_num_segments = 13
    assert len(segment_paths) == exp_num_segments
    assert all(p.exists() and isinstance(p, Path) for p in segment_paths)
    assert isinstance(segments_playlist_file, Path)
    assert segments_playlist_file.exists()

    assert codecs_string == 'avc1.640028,mp4a.40.2'

    segment_names_durations = [
        (p.name, services.get_metadata(p)['summary']['duration'])
        for p in segment_paths
    ]
    exp_segment_names_durations = [
        ('0.ts', 9.2092),
        ('1.ts', 3.3033),
        ('2.ts', 4.337667),
        ('3.ts', 7.540867),
        ('4.ts', 4.537867),
        ('5.ts', 4.6046),
        ('6.ts', 6.006),
        ('7.ts', 8.341667),
        ('8.ts', 3.036367),
        ('9.ts', 6.773433),
        ('10.ts', 5.472133),
        ('11.ts', 8.341667),
        ('12.ts', 5.9059),
    ]
    for actual, expected in zip(
        segment_names_durations, exp_segment_names_durations
    ):
        actual_name, actual_duration = actual
        expected_name, expected_duration = expected
        assert actual_name == expected_name
        assert actual_duration == pytest.approx(expected_duration, 0.5)

    bucket = settings.BUCKET_MEDIA
    exp_playlist = f"""
    #EXTM3U
    #EXT-X-VERSION:3
    #EXT-X-TARGETDURATION:9
    #EXT-X-MEDIA-SEQUENCE:0
    #EXT-X-PLAYLIST-TYPE:VOD
    #EXTINF:9.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/0.ts
    #EXTINF:3.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/1.ts
    #EXTINF:4.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/2.ts
    #EXTINF:7.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/3.ts
    #EXTINF:4.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/4.ts
    #EXTINF:4.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/5.ts
    #EXTINF:6.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/6.ts
    #EXTINF:8.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/7.ts
    #EXTINF:3.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/8.ts
    #EXTINF:6.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/9.ts
    #EXTINF:5.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/10.ts
    #EXTINF:8.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/11.ts
    #EXTINF:5.01,
    /{bucket}/videos/{video_id}/renditions/{video_rendition_id}/segments/12.ts
    #EXT-X-ENDLIST
    """
    actual = m3u8.load(str(segments_playlist_file)).dumps()
    expected = m3u8.loads(exp_playlist).dumps().replace('.01', '.+')
    assert re.match(expected, actual)
Esempio n. 9
0
    def test_get(
        self,
        api_client_no_auth,
        video_factory,
        transcode_job_factory,
        mocker,
        simple_uploaded_file_factory,
        rendition_playlist_file,
    ):
        video = video_factory(
            video_path=VIDEO_PATH,
            description='description',
            tags=['tag1', 'tag2'],
            visibility='draft',
            title='title',
        )
        file_ = simple_uploaded_file_factory(video_path=VIDEO_PATH)
        models.VideoRendition.objects.create(
            video=video,
            file=file_,
            playlist_file=rendition_playlist_file,
            file_size=1000,
            width=256,
            height=144,
            duration=10,
            ext='webm',
            container='webm',
            audio_codec='opus',
            video_codec='vp9',
            name='144p',
            framerate=30,
            metadata=services.get_metadata(VIDEO_PATH),
        )

        response = api_client_no_auth.get(
            f'/api/v1/video/{video.id}/playlist.m3u8')

        assert response.status_code == OK
        resp_text = response.content.decode()
        assert resp_text.startswith('#EXTM3U')
        assert m3u8.loads(resp_text).data == {
            'iframe_playlists': [],
            'is_endlist':
            False,
            'is_i_frames_only':
            False,
            'is_independent_segments':
            False,
            'is_variant':
            True,
            'keys': [],
            'media': [],
            'media_sequence':
            None,
            'part_inf': {},
            'playlist_type':
            None,
            'playlists': [{
                'stream_info': {
                    'bandwidth': 182464,
                    'closed_captions': 'NONE',
                    'program_id': 1,
                    'resolution': '256x144',
                },
                'uri': mocker.ANY,
            }],
            'rendition_reports': [],
            'segments': [],
            'session_data': [],
            'session_keys': [],
            'skip': {},
        }