Beispiel #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="StreamInfo"/> class.
        /// </summary>
        /// <param name="stream">A generic stream.</param>
        /// <param name="container">The input container.</param>
        internal unsafe StreamInfo(AVStream *stream, InputContainer container)
        {
            var codec = stream->codec;

            Metadata     = new ReadOnlyDictionary <string, string>(FFDictionary.ToDictionary(stream->metadata));
            CodecName    = ffmpeg.avcodec_get_name(codec->codec_id);
            CodecId      = codec->codec_id.FormatEnum(12);
            Index        = stream->index;
            IsInterlaced = codec->field_order != AVFieldOrder.AV_FIELD_PROGRESSIVE &&
                           codec->field_order != AVFieldOrder.AV_FIELD_UNKNOWN;
            TimeBase = stream->time_base;
            Duration = stream->duration >= 0
                ? stream->duration.ToTimeSpan(stream->time_base)
                : TimeSpan.FromTicks(container.Pointer->duration * 10);
            var start = stream->start_time.ToTimeSpan(stream->time_base);

            StartTime = start == TimeSpan.MinValue ? TimeSpan.Zero : start;

            if (stream->nb_frames > 0)
            {
                IsFrameCountProvidedByContainer = true;
                FrameCount = (int)stream->nb_frames;
            }
            else
            {
                FrameCount = Duration.ToFrameNumber(stream->avg_frame_rate);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Extracts the chapters from the input.
        /// </summary>
        /// <param name="ic">The ic.</param>
        /// <returns>The chapters.</returns>
        private static List <ChapterInfo> ExtractChapters(AVFormatContext *ic)
        {
            var result = new List <ChapterInfo>(128);

            if (ic->chapters == null)
            {
                return(result);
            }

            for (var i = 0; i < ic->nb_chapters; i++)
            {
                var c = ic->chapters[i];

                var chapter = new ChapterInfo
                {
                    StartTime = c->start.ToTimeSpan(c->time_base),
                    EndTime   = c->end.ToTimeSpan(c->time_base),
                    Index     = i,
                    ChapterId = c->id,
                    Metadata  = FFDictionary.ToDictionary(c->metadata)
                };

                result.Add(chapter);
            }

            return(result);
        }
Beispiel #3
0
        /// <summary>
        /// Extracts the stream infos from the input.
        /// </summary>
        /// <param name="inputContext">The input context.</param>
        /// <returns>The list of stream infos.</returns>
        private static List <StreamInfo> ExtractStreams(AVFormatContext *inputContext)
        {
            var result = new List <StreamInfo>(32);

            if (inputContext->streams == null)
            {
                return(result);
            }

            for (var i = 0; i < inputContext->nb_streams; i++)
            {
                var s = inputContext->streams[i];

                var codecContext = ffmpeg.avcodec_alloc_context3(null);

#pragma warning disable CS0618 // Type or member is obsolete

                // ffmpeg.avcodec_parameters_to_context(codecContext, s->codecpar);
                ffmpeg.avcodec_copy_context(codecContext, s->codec);
#pragma warning restore CS0618 // Type or member is obsolete

                var bitsPerSample = codecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO ?
                                    ffmpeg.av_get_bits_per_sample(codecContext->codec_id) : 0;

                var stream = new StreamInfo
                {
                    StreamId            = s->id,
                    StreamIndex         = s->index,
                    Metadata            = FFDictionary.ToDictionary(s->metadata),
                    CodecType           = codecContext->codec_type,
                    CodecTypeName       = ffmpeg.av_get_media_type_string(codecContext->codec_type),
                    Codec               = codecContext->codec_id,
                    CodecName           = ffmpeg.avcodec_get_name(codecContext->codec_id),
                    CodecProfile        = ffmpeg.avcodec_profile_name(codecContext->codec_id, codecContext->profile),
                    ReferenceFrameCount = codecContext->refs,
                    CodecTag            = codecContext->codec_tag,
                    PixelFormat         = codecContext->pix_fmt,
                    FieldOrder          = codecContext->field_order,
                    IsInterlaced        = codecContext->field_order != AVFieldOrder.AV_FIELD_PROGRESSIVE &&
                                          codecContext->field_order != AVFieldOrder.AV_FIELD_UNKNOWN,
                    ColorRange        = codecContext->color_range,
                    PixelWidth        = codecContext->width,
                    PixelHeight       = codecContext->height,
                    HasClosedCaptions = (codecContext->properties & ffmpeg.FF_CODEC_PROPERTY_CLOSED_CAPTIONS) != 0,
                    IsLossless        = (codecContext->properties & ffmpeg.FF_CODEC_PROPERTY_LOSSLESS) != 0,
                    Channels          = codecContext->channels,
                    BitRate           = bitsPerSample > 0 ?
                                        bitsPerSample * codecContext->channels * codecContext->sample_rate :
                                        codecContext->bit_rate,
                    MaxBitRate         = codecContext->rc_max_rate,
                    InfoFrameCount     = s->codec_info_nb_frames,
                    TimeBase           = s->time_base,
                    SampleFormat       = codecContext->sample_fmt,
                    SampleRate         = codecContext->sample_rate,
                    DisplayAspectRatio = codecContext->height > 0 ?
                                         ffmpeg.av_d2q((double)codecContext->width / codecContext->height, int.MaxValue) :
Beispiel #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="StreamInfo"/> class.
        /// </summary>
        /// <param name="stream">The video stream.</param>
        /// <param name="container">The input container.</param>
        internal unsafe StreamInfo(AVStream *stream, InputContainer container)
        {
            var codec = stream->codec;

            Metadata     = new ReadOnlyDictionary <string, string>(FFDictionary.ToDictionary(stream->metadata));
            CodecName    = ffmpeg.avcodec_get_name(codec->codec_id);
            CodecId      = codec->codec_id.FormatEnum(12);
            Index        = stream->index;
            IsInterlaced = codec->field_order != AVFieldOrder.AV_FIELD_PROGRESSIVE &&
                           codec->field_order != AVFieldOrder.AV_FIELD_UNKNOWN;
            FrameSize           = new Size(codec->width, codec->height);
            PixelFormat         = codec->pix_fmt.FormatEnum(11);
            AVPixelFormat       = codec->pix_fmt;
            TimeBase            = stream->time_base;
            RealFrameRate       = stream->r_frame_rate;
            AvgFrameRate        = stream->avg_frame_rate.ToDouble();
            IsVariableFrameRate = RealFrameRate.ToDouble() != AvgFrameRate;

            if (stream->duration >= 0)
            {
                Duration    = stream->duration.ToTimeSpan(stream->time_base);
                DurationRaw = stream->duration;
            }
            else
            {
                Duration    = TimeSpan.FromTicks(container.Pointer->duration * 10);
                DurationRaw = Duration.ToTimestamp(TimeBase);
            }

            var start = stream->start_time.ToTimeSpan(stream->time_base);

            StartTime = start == TimeSpan.MinValue ? TimeSpan.Zero : start;

            if (stream->nb_frames > 0)
            {
                IsFrameCountProvidedByContainer = true;
                NumberOfFrames = (int)stream->nb_frames;
                FrameCount     = NumberOfFrames.Value;
            }
            else
            {
                FrameCount = Duration.ToFrameNumber(stream->avg_frame_rate);
                if (!IsVariableFrameRate)
                {
                    NumberOfFrames = FrameCount;
                }
                else
                {
                    NumberOfFrames = null;
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MediaInfo"/> class.
        /// </summary>
        /// <param name="container">The input container context.</param>
        internal unsafe MediaInfo(AVFormatContext *container)
        {
            FilePath        = new IntPtr(container->url).Utf8ToString();
            ContainerFormat = new IntPtr(container->iformat->name).Utf8ToString();
            Metadata        = new ReadOnlyDictionary <string, string>(FFDictionary.ToDictionary(container->metadata));
            Bitrate         = container->bit_rate > 0 ? container->bit_rate : 0;

            var timeBase = new AVRational {
                num = 1, den = ffmpeg.AV_TIME_BASE
            };

            Duration  = container->duration != ffmpeg.AV_NOPTS_VALUE ? container->duration.ToTimeSpan(timeBase) : TimeSpan.Zero;
            StartTime = container->start_time != ffmpeg.AV_NOPTS_VALUE ? container->start_time.ToTimeSpan(timeBase) : TimeSpan.Zero;
        }
Beispiel #6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="StreamInfo"/> class.
        /// </summary>
        /// <param name="stream">A generic stream.</param>
        /// <param name="type">The media type of the stream.</param>
        /// <param name="container">The input container.</param>
        internal unsafe StreamInfo(AVStream *stream, MediaType type, InputContainer container)
        {
            var codec = stream->codec;

            Metadata  = new ReadOnlyDictionary <string, string>(FFDictionary.ToDictionary(stream->metadata));
            CodecName = ffmpeg.avcodec_get_name(codec->codec_id);
            CodecId   = codec->codec_id.FormatEnum(12);
            Index     = stream->index;
            Type      = type;

            TimeBase            = stream->time_base;
            RealFrameRate       = stream->r_frame_rate;
            AvgFrameRate        = stream->avg_frame_rate.ToDouble();
            IsVariableFrameRate = RealFrameRate.ToDouble() != AvgFrameRate;

            if (stream->duration >= 0)
            {
                Duration    = stream->duration.ToTimeSpan(stream->time_base);
                DurationRaw = stream->duration;
            }
            else
            {
                Duration    = TimeSpan.FromTicks(container.Pointer->duration * 10);
                DurationRaw = Duration.ToTimestamp(TimeBase);
            }

            if (stream->start_time >= 0)
            {
                StartTime = stream->start_time.ToTimeSpan(stream->time_base);
            }

            if (stream->nb_frames > 0)
            {
                IsFrameCountProvidedByContainer = true;
                NumberOfFrames = (int)stream->nb_frames;
                FrameCount     = NumberOfFrames.Value;
            }
            else
            {
                FrameCount = Duration.ToFrameNumber(stream->avg_frame_rate);
                if (!IsVariableFrameRate)
                {
                    NumberOfFrames = FrameCount;
                }
                else
                {
                    NumberOfFrames = null;
                }
            }
        }
Beispiel #7
0
        private static unsafe StreamChapter[] ParseChapters(InputContainer container)
        {
            var streamChapters = new StreamChapter[container.Pointer->nb_chapters];

            for (var i = 0; i < container.Pointer->nb_chapters; i++)
            {
                var chapter       = container.Pointer->chapters[i];
                var meta          = chapter->metadata;
                var startTimespan = TimeSpan.FromTicks(chapter->start / 100);
                var endTimespan   = TimeSpan.FromTicks(chapter->end / 100);
                streamChapters[i] = new StreamChapter(startTimespan, endTimespan, FFDictionary.ToDictionary(meta, true));
            }

            return(streamChapters);
        }
Beispiel #8
0
        private static unsafe MediaChapter[] ParseChapters(AVFormatContext *container)
        {
            var streamChapters = new MediaChapter[container->nb_chapters];

            for (var i = 0; i < container->nb_chapters; i++)
            {
                var chapter       = container->chapters[i];
                var meta          = chapter->metadata;
                var startTimespan = chapter->start.ToTimeSpan(chapter->time_base);
                var endTimespan   = chapter->end.ToTimeSpan(chapter->time_base);
                streamChapters[i] =
                    new MediaChapter(startTimespan, endTimespan, FFDictionary.ToDictionary(meta, true));
            }

            return(streamChapters);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="StreamInfo"/> class.
        /// </summary>
        /// <param name="stream">The video stram.</param>
        internal unsafe StreamInfo(AVStream *stream)
        {
            var codec = stream->codec;

            Metadata     = new ReadOnlyDictionary <string, string>(FFDictionary.ToDictionary(stream->metadata));
            CodecName    = ffmpeg.avcodec_get_name(codec->codec_id);
            CodecId      = FormatCodecId(codec->codec_id);
            Index        = stream->index;
            IsInterlaced = codec->field_order != AVFieldOrder.AV_FIELD_PROGRESSIVE && codec->field_order != AVFieldOrder.AV_FIELD_UNKNOWN;
            FrameSize    = new Size(codec->width, codec->height);
            PixelFormat  = codec->pix_fmt;
            TimeBase     = stream->time_base;
            RFrameRate   = stream->r_frame_rate;
            FrameRate    = RFrameRate.ToDouble();
            Duration     = stream->duration.ToTimeSpan(stream->time_base);
            var start = stream->start_time.ToTimeSpan(stream->time_base);

            StartTime  = start == TimeSpan.MinValue ? TimeSpan.Zero : start;
            FrameCount = Duration.ToFrameNumber(RFrameRate);
        }
Beispiel #10
0
        /// <summary>
        /// Extracts the programs from the input and creates associations between programs and streams.
        /// </summary>
        /// <param name="ic">The ic.</param>
        /// <param name="streams">The streams.</param>
        /// <returns>The program information.</returns>
        private static List <ProgramInfo> ExtractPrograms(AVFormatContext *ic, IReadOnlyDictionary <int, StreamInfo> streams)
        {
            var result = new List <ProgramInfo>(128);

            if (ic->programs == null)
            {
                return(result);
            }

            for (var i = 0; i < ic->nb_programs; i++)
            {
                var p = ic->programs[i];

                var program = new ProgramInfo
                {
                    Metadata      = FFDictionary.ToDictionary(p->metadata),
                    ProgramId     = p->id,
                    ProgramNumber = p->program_num
                };

                var associatedStreams = new List <StreamInfo>(32);
                for (var s = 0; s < p->nb_stream_indexes; s++)
                {
                    var streamIndex = Convert.ToInt32(p->stream_index[s]);
                    if (streams.ContainsKey(streamIndex))
                    {
                        associatedStreams.Add(streams[streamIndex]);
                    }
                }

                program.Streams = associatedStreams;

                result.Add(program);
            }

            return(result);
        }
Beispiel #11
0
        /// <summary>
        /// Extracts the programs from the input and creates associations between programs and streams.
        /// </summary>
        /// <param name="ic">The ic.</param>
        /// <param name="streams">The streams.</param>
        /// <returns>The program information</returns>
        private static List <ProgramInfo> ExtractPrograms(AVFormatContext *ic, ReadOnlyDictionary <int, StreamInfo> streams)
        {
            var result = new List <ProgramInfo>();

            if (ic->programs == null)
            {
                return(result);
            }

            for (var i = 0; i < ic->nb_programs; i++)
            {
                var p = ic->programs[i];

                var program = new ProgramInfo
                {
                    Metadata      = new ReadOnlyDictionary <string, string>(FFDictionary.ToDictionary(p->metadata)),
                    ProgramId     = p->id,
                    ProgramNumber = p->program_num,
                };

                var associatedStreams = new List <StreamInfo>();
                for (var s = 0; s < p->nb_stream_indexes; s++)
                {
                    var streamIndex = (int)p->stream_index[s];
                    if (streams.ContainsKey(streamIndex))
                    {
                        associatedStreams.Add(streams[streamIndex]);
                    }
                }

                program.Streams = new ReadOnlyCollection <StreamInfo>(associatedStreams);

                result.Add(program);
            }

            return(result);
        }
Beispiel #12
0
        /// <summary>
        /// Extracts the stream infos from the input.
        /// </summary>
        /// <param name="inputContext">The input context.</param>
        /// <returns>The list of stream infos.</returns>
        private static List <StreamInfo> ExtractStreams(AVFormatContext *inputContext)
        {
            var result = new List <StreamInfo>(32);

            if (inputContext->streams == null)
            {
                return(result);
            }

            for (var i = 0; i < inputContext->nb_streams; i++)
            {
                var s = inputContext->streams[i];

                var codecContext = ffmpeg.avcodec_alloc_context3(null);
                ffmpeg.avcodec_parameters_to_context(codecContext, s->codecpar);

                // Fields which are missing from AVCodecParameters need to be taken
                // from the stream's AVCodecContext
                codecContext->properties   = s->codec->properties;
                codecContext->codec        = s->codec->codec;
                codecContext->qmin         = s->codec->qmin;
                codecContext->qmax         = s->codec->qmax;
                codecContext->coded_width  = s->codec->coded_height;
                codecContext->coded_height = s->codec->coded_width;

                var bitsPerSample = codecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO ?
                                    ffmpeg.av_get_bits_per_sample(codecContext->codec_id) : 0;

                var dar      = s->display_aspect_ratio;
                var sar      = s->sample_aspect_ratio;
                var codecSar = s->codecpar->sample_aspect_ratio;

                if (sar.num != 0 && (sar.num != codecSar.num || sar.den != codecSar.den))
                {
                    ffmpeg.av_reduce(
                        &dar.num,
                        &dar.den,
                        s->codecpar->width * sar.num,
                        s->codecpar->height * sar.den,
                        1024 * 1024);
                }

                var stream = new StreamInfo
                {
                    StreamId            = s->id,
                    StreamIndex         = s->index,
                    Metadata            = FFDictionary.ToDictionary(s->metadata),
                    CodecType           = codecContext->codec_type,
                    CodecTypeName       = ffmpeg.av_get_media_type_string(codecContext->codec_type),
                    Codec               = codecContext->codec_id,
                    CodecName           = ffmpeg.avcodec_get_name(codecContext->codec_id),
                    CodecProfile        = ffmpeg.avcodec_profile_name(codecContext->codec_id, codecContext->profile),
                    ReferenceFrameCount = codecContext->refs,
                    CodecTag            = codecContext->codec_tag,
                    PixelFormat         = codecContext->pix_fmt,
                    FieldOrder          = codecContext->field_order,
                    IsInterlaced        = codecContext->field_order != AVFieldOrder.AV_FIELD_PROGRESSIVE &&
                                          codecContext->field_order != AVFieldOrder.AV_FIELD_UNKNOWN,
                    ColorRange        = codecContext->color_range,
                    PixelWidth        = codecContext->width,
                    PixelHeight       = codecContext->height,
                    HasClosedCaptions = (codecContext->properties & ffmpeg.FF_CODEC_PROPERTY_CLOSED_CAPTIONS) != 0,
                    IsLossless        = (codecContext->properties & ffmpeg.FF_CODEC_PROPERTY_LOSSLESS) != 0,
                    BitRate           = bitsPerSample > 0 ?
                                        bitsPerSample * codecContext->channels * codecContext->sample_rate :
                                        codecContext->bit_rate,
                    MaxBitRate         = codecContext->rc_max_rate,
                    InfoFrameCount     = s->codec_info_nb_frames,
                    TimeBase           = s->time_base,
                    SampleFormat       = codecContext->sample_fmt,
                    SampleRate         = codecContext->sample_rate,
                    DisplayAspectRatio = dar,
                    SampleAspectRatio  = sar,
                    Disposition        = s->disposition,
                    StartTime          = s->start_time.ToTimeSpan(s->time_base),
                    Duration           = s->duration.ToTimeSpan(s->time_base),
                    FPS = s->avg_frame_rate.ToDouble(),
                    TBR = s->r_frame_rate.ToDouble(),
                    TBN = 1d / s->time_base.ToDouble(),
                    TBC = 1d / s->codec->time_base.ToDouble()
                };

                // Extract valid hardware configurations
                stream.HardwareDevices  = HardwareAccelerator.GetCompatibleDevices(stream.Codec);
                stream.HardwareDecoders = GetHardwareDecoders(stream.Codec);

                // TODO: I chose not to include Side data but I could easily do so
                // https://ffmpeg.org/doxygen/3.2/dump_8c_source.html
                // See function: dump_sidedata
                ffmpeg.avcodec_free_context(&codecContext);

                result.Add(stream);
            }

            return(result);
        }