File size: 5,835 Bytes
6755a2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
from __future__ import annotations

from functools import partial
import json
import os
from tracemalloc import start
from typing import List
import logging

import cv2
import numpy as np
from moviepy.editor import (
    VideoFileClip,
    concatenate_videoclips,
    vfx,
    CompositeVideoClip,
    TextClip,
)
import ffmpeg

from ...data import Item, Items
from ...data import MetaInfo
from ...utils.time_util import timestr_2_seconds
from ...utils.util import convert_class_attr_to_dict
from .video_clip import VideoClipSeq

logger = logging.getLogger(__name__)  # pylint: disable=invalid-name


class VideoMetaInfo(MetaInfo):
    def __init__(
        self,
        mediaid=None,
        media_duration=None,
        media_path=None,
        media_map_path=None,
        media_name=None,
        signature: str = None,
        height: int = None,
        width: int = None,
        target_width: int = None,
        target_height: int = None,
        start: float = None,
        end: float = None,
        ext: str = None,
        other_channels=None,
        content_box: List[float] = None,
        **kwargs,
    ):
        """_summary_

        Args:
            video_path (_type_, optional): _description_. Defaults to None.
            videoinfo_path (_type_, optional): _description_. Defaults to None.
        """

        self.width = width
        self.height = height
        self.target_width = target_width
        self.target_height = target_height
        self.other_channels = other_channels
        self.content_box = content_box
        super().__init__(
            mediaid,
            media_name,
            media_duration,
            signature,
            media_path,
            media_map_path,
            start,
            end,
            ext,
            **kwargs,
        )

    def preprocess(self):
        super().preprocess()
        self.set_content_box()

    def set_content_box(self):
        if self.content_box is None:
            self.content_box = [
                0,
                0,
                self.width,
                self.height,
            ]
        self.content_width = self.content_box[2] - self.content_box[0]
        self.content_height = self.content_box[3] - self.content_box[1]

    @classmethod
    def from_video_path(cls, path) -> VideoMetaInfo:
        filename = os.path.splitext(os.path.basename(path))[0]
        video_channel, other_channels = get_metainfo_by_ffmpeg(path)
        return VideoMetaInfo(
            mediaid=filename, other_channels=other_channels, **video_channel
        )

    @classmethod
    def from_data(cls, data) -> VideoMetaInfo:
        return VideoMetaInfo(**data)


def get_metainfo_by_opencv(path: str) -> dict:
    """使用opencv获取视频的元信息,主要有width, height, frame_count, fps

    Args:
        path (str): 视频路径

    Returns:
        dict: 视频相关信息,
    """
    cap = cv2.VideoCapture(path)
    dct = {}
    # Check if camera opened successfully
    if not cap.isOpened():
        logger.error("Error opening video stream or file")
    dct["width"] = cap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)  # float `width`
    dct["height"] = cap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)  # float `height`
    dct["frame_count"] = cap.get(cv2.CAP_PROP_FRAME_COUNT)
    dct["fps"] = cap.get(cv2.cv.CV_CAP_PROP_FPS)
    return dct, None


def get_metainfo_by_ffmpeg(path: str) -> dict:
    dct = {}
    multi_channels_info = ffmpeg.probe(path)["streams"]
    other_channels = [
        channel for channel in multi_channels_info if channel["codec_type"] != "video"
    ]
    video_channel = [
        channel for channel in multi_channels_info if channel["codec_type"] == "video"
    ][0]
    if "duration" in video_channel:
        video_duration = video_channel["duration"]
    elif "DURATION" in video_channel:
        video_duration = video_channel["DURATION"]
    elif "DURATION-en" in video_channel:
        video_duration = video_channel["DURATION-en"]
    elif "DURATION-eng" in video_channel:
        video_duration = video_channel["DURATION-eng"]
    elif "tags" in video_channel and "duration" in video_channel["tags"]:
        video_duration = video_channel["tags"]["duration"]
    elif "tags" in video_channel and "DURATION" in video_channel["tags"]:
        video_duration = video_channel["tags"]["DURATION"]
    elif "tags" in video_channel and "DURATION-en" in video_channel["tags"]:
        video_duration = video_channel["tags"]["DURATION-en"]
    elif "tags" in video_channel and "DURATION-eng" in video_channel["tags"]:
        video_duration = video_channel["tags"]["DURATION-eng"]
    else:
        logger.warning("cant find video_duration :{}".format(path))
        video_duration = None
    if video_duration is not None:
        video_duration = timestr_2_seconds(video_duration)
    avg_frame_rate = float(video_channel["avg_frame_rate"].split("/")[0]) / float(
        video_channel["avg_frame_rate"].split("/")[1]
    )
    time_base = float(video_channel["time_base"].split("/")[0]) / float(
        video_channel["time_base"].split("/")[1]
    )
    start_pts = (
        int(float(video_channel["start_pts"])) if "start_pts" in video_channel else None
    )
    start_time = (
        int(float(video_channel["start_time"]))
        if "start_time" in video_channel
        else None
    )
    dct = {
        "media_duration": video_duration,
        "height": int(video_channel["height"]),
        "width": int(video_channel["width"]),
        "codec_type": video_channel["codec_type"],
        # "display_aspect_ratio": video_channel["display_aspect_ratio"],
        "avg_frame_rate": avg_frame_rate,
        "time_base": time_base,
        "start_pts": start_pts,
        "start_time": start_time,
        "fps": avg_frame_rate,
    }
    return dct, other_channels