"""Extract metadata.""" from decimal import Decimal import json from pymediainfo import MediaInfo from video.connectors import s3 as s3_connector from video.constants import assets from video.constants import job_io_fields from video.logic.activity_task_logger import activity_task_logger from video.models import ows_video def format_value(caster, value): """Format values.""" if value is None: return value return caster(str(value).strip().lower()) def _extract_metadata(video_s3_key): """Extract metadata. Args: inputs (dict): Inputs. Returns: dict: Outputs. """ video_s3_url = s3_connector.get_url_for_s3_object( assets.VIDEO_S3_BUCKET, video_s3_key) metadata = MediaInfo.parse(video_s3_url) container, = [ stream for stream in metadata.tracks if stream.track_type == 'General'] video_streams = [ stream for stream in metadata.tracks if stream.track_type == 'Video'] audio_streams = [ stream for stream in metadata.tracks if stream.track_type == 'Audio'] outputs = {} num_video_streams = ( format_value(int, container.count_of_video_streams) or 0) num_audio_streams = ( format_value(int, container.count_of_audio_streams) or 0) outputs.update({ job_io_fields.NUM_VIDEO_STREAMS: num_video_streams, job_io_fields.NUM_AUDIO_STREAMS: num_audio_streams, job_io_fields.CONTAINER_FORMAT: format_value(str, container.format), job_io_fields.CONTAINER_FORMAT_PROFILE: format_value(str, container.format_profile), }) if num_video_streams == 1: video_stream, = video_streams outputs.update({ job_io_fields.VIDEO_STREAM_CODEC: format_value(str, video_stream.format), job_io_fields.VIDEO_STREAM_CODEC_PROFILE: format_value(str, video_stream.format_profile), job_io_fields.VIDEO_STREAM_WIDTH_PIXELS: format_value(int, video_stream.width), job_io_fields.VIDEO_STREAM_HEIGHT_PIXELS: format_value(int, video_stream.height), job_io_fields.VIDEO_STREAM_BIT_RATE_BITS_PER_SECOND: format_value(int, video_stream.bit_rate), job_io_fields.VIDEO_STREAM_DURATION_SECONDS: float(Decimal( str(format_value(float, video_stream.duration))) / 1000), job_io_fields.VIDEO_STREAM_FRAME_RATE_FRAMES_PER_SECOND: format_value(float, video_stream.frame_rate), job_io_fields.VIDEO_STREAM_PIXEL_ASPECT_RATIO: format_value(float, video_stream.pixel_aspect_ratio), }) if num_audio_streams == 1: audio_stream, = audio_streams outputs.update({ job_io_fields.AUDIO_STREAM_CODEC: format_value(str, audio_stream.format), job_io_fields.AUDIO_STREAM_CODEC_PROFILE: format_value( str, audio_stream.format_profile or audio_stream.format_additionalfeatures), job_io_fields.AUDIO_STREAM_BIT_RATE_BITS_PER_SECOND: format_value(int, audio_stream.bit_rate), job_io_fields.AUDIO_STREAM_BIT_DEPTH_BITS: format_value(int, audio_stream.bit_depth), job_io_fields.AUDIO_STREAM_DURATION_SECONDS: float(Decimal( str(format_value(float, audio_stream.duration))) / 1000), job_io_fields.AUDIO_STREAM_CHANNEL_COUNT: format_value(int, audio_stream.channel_s), job_io_fields.AUDIO_STREAM_CHANNEL_LAYOUT: format_value(str, audio_stream.channel_layout), job_io_fields.AUDIO_STREAM_SAMPLE_RATE_SAMPLES_PER_SECOND: format_value(int, audio_stream.sampling_rate), }) return outputs @activity_task_logger([ job_io_fields.INPUT_VIDEO_S3_BUCKET, job_io_fields.INPUT_VIDEO_S3_KEY, ]) def extract_metadata(inputs): """Extract metadata. Args: inputs (dict): Inputs. Returns: dict: Outputs. """ return _extract_metadata(inputs[job_io_fields.INPUT_VIDEO_S3_KEY]) @activity_task_logger([ job_io_fields.PRORES_MEZZANINE_OUTPUT_S3_KEY, job_io_fields.PRODUCT_ID, ]) def extract_prores_mezzanine_metadata(inputs): """Extract prores mezzanine metadata. Args: inputs (dict): Inputs. Returns: dict: Outputs. """ data = _extract_metadata( inputs[job_io_fields.PRORES_MEZZANINE_OUTPUT_S3_KEY]) ows_video_response = ows_video.set_track_metadata( {**data, job_io_fields.PRODUCT_ID: inputs[job_io_fields.PRODUCT_ID]}) outputs = { job_io_fields.PRORES_MEZZANINE_METADATA: json.dumps(data), job_io_fields.TUID: ows_video_response['track_id'], } return outputs