Esempio n. 1
0
        /// <summary>
        /// Opens the video stream with the specified index in the media container.
        /// </summary>
        /// <param name="container">The media container.</param>
        /// <param name="index">The video stream index.</param>
        /// <param name="options">The media options.</param>
        /// <returns>The opened <see cref="InputStream{TFrame}"/>.</returns>
        internal static InputStream <VideoFrame> OpenVideo(InputContainer container, int index, MediaOptions options)
        {
            var format       = container.Pointer;
            var stream       = format->streams[index];
            var codecContext = stream->codec;

            codecContext->pkt_timebase = stream->time_base;

            var codec = ffmpeg.avcodec_find_decoder(codecContext->codec_id);

            if (codec == null)
            {
                throw new InvalidOperationException("Cannot find a codec for this stream.");
            }

            var dict = new FFDictionary(options.DecoderOptions);
            var ptr  = dict.Pointer;

            ffmpeg.avcodec_open2(codecContext, codec, &ptr)
            .ThrowIfError("Cannot open the video codec");

            dict.Update(ptr);

            return(new InputStream <VideoFrame>(stream, container));
        }
        /// <summary>
        /// Creates a new video stream for the specified <see cref="OutputContainer"/>.
        /// </summary>
        /// <param name="container">The media container.</param>
        /// <param name="config">The stream settings.</param>
        /// <returns>The new video stream.</returns>
        public static OutputStream <VideoFrame> CreateVideo(OutputContainer container, VideoEncoderSettings config)
        {
            var codecId = config.Codec ?? container.Pointer->oformat->video_codec;

            if (codecId == AVCodecID.AV_CODEC_ID_NONE)
            {
                throw new InvalidOperationException("The media container doesn't support video!");
            }

            var codec = ffmpeg.avcodec_find_encoder(codecId);

            if (codec == null)
            {
                throw new InvalidOperationException($"Cannot find an encoder with the {codecId}!");
            }

            if (codec->type != AVMediaType.AVMEDIA_TYPE_VIDEO)
            {
                throw new InvalidOperationException($"The {codecId} encoder doesn't support video!");
            }

            var videoStream  = ffmpeg.avformat_new_stream(container.Pointer, codec);
            var codecContext = videoStream->codec;

            codecContext->codec_id   = codecId;
            codecContext->codec_type = AVMediaType.AVMEDIA_TYPE_VIDEO;

            codecContext->bit_rate = config.Bitrate;
            codecContext->width    = config.VideoWidth;
            codecContext->height   = config.VideoHeight;

            codecContext->time_base.den = config.Framerate;
            codecContext->time_base.num = 1;
            codecContext->gop_size      = config.KeyframeRate;
            codecContext->pix_fmt       = (AVPixelFormat)config.VideoFormat;

            if ((container.Pointer->oformat->flags & ffmpeg.AVFMT_GLOBALHEADER) != 0)
            {
                codecContext->flags |= ffmpeg.AV_CODEC_FLAG_GLOBAL_HEADER;
            }

            var dict = new FFDictionary(config.CodecOptions);
            var ptr  = dict.Pointer;

            ffmpeg.avcodec_open2(codecContext, codec, &ptr);

            dict.Update(ptr);

            return(new OutputStream <VideoFrame>(videoStream, container));
        }
        /// <summary>
        /// Creates a new audio stream for the specified <see cref="OutputContainer"/>.
        /// </summary>
        /// <param name="container">The media container.</param>
        /// <param name="config">The stream settings.</param>
        /// <returns>The new audio stream.</returns>
        public static OutputStream <AudioFrame> CreateAudio(OutputContainer container, AudioEncoderSettings config)
        {
            var codecId = config.Codec == AudioCodec.Default ? container.Pointer->oformat->audio_codec : (AVCodecID)config.Codec;

            if (codecId == AVCodecID.AV_CODEC_ID_NONE)
            {
                throw new InvalidOperationException("The media container doesn't support audio!");
            }

            var codec = ffmpeg.avcodec_find_encoder(codecId);

            if (codec == null)
            {
                throw new InvalidOperationException($"Cannot find an encoder with the {codecId}!");
            }

            if (codec->type != AVMediaType.AVMEDIA_TYPE_AUDIO)
            {
                throw new InvalidOperationException($"The {codecId} encoder doesn't support audio!");
            }

            var audioStream  = ffmpeg.avformat_new_stream(container.Pointer, codec);
            var codecContext = audioStream->codec;

            codecContext->time_base = config.TimeBase;

            codecContext->codec_id   = codecId;
            codecContext->codec_type = AVMediaType.AVMEDIA_TYPE_AUDIO;

            codecContext->bit_rate       = config.Bitrate;
            codecContext->sample_rate    = config.SampleRate;
            codecContext->frame_size     = config.SamplesPerFrame;
            codecContext->sample_fmt     = (AVSampleFormat)config.SampleFormat;
            codecContext->channels       = config.Channels;
            codecContext->channel_layout = (ulong)ffmpeg.av_get_default_channel_layout(config.Channels);

            if ((container.Pointer->oformat->flags & ffmpeg.AVFMT_GLOBALHEADER) != 0)
            {
                codecContext->flags |= ffmpeg.AV_CODEC_FLAG_GLOBAL_HEADER;
            }

            var dict = new FFDictionary(config.CodecOptions);
            var ptr  = dict.Pointer;

            ffmpeg.avcodec_open2(codecContext, codec, &ptr);

            dict.Update(ptr);

            return(new OutputStream <AudioFrame>(audioStream, container));
        }
Esempio n. 4
0
        /// <summary>
        /// Opens a media container and stream codecs from given path.
        /// </summary>
        /// <param name="path">A path to the multimedia file.</param>
        /// <param name="options">The media settings.</param>
        /// <returns>A new instance of the <see cref="InputContainer"/> class.</returns>
        public static InputContainer LoadFile(string path, MediaOptions options)
        {
            MediaToolkit.LoadFFmpeg();

            var context = ffmpeg.avformat_alloc_context();

            options.DemuxerOptions.ApplyFlags(context);
            var dict = new FFDictionary(options.DemuxerOptions.PrivateOptions);
            var ptr  = dict.Pointer;

            ffmpeg.avformat_open_input(&context, path, null, &ptr)
            .ThrowIfError("An error ocurred while opening the file");

            ffmpeg.avformat_find_stream_info(context, null)
            .ThrowIfError("Cannot find stream info");

            dict.Update(ptr);

            var container = new InputContainer(context);

            container.OpenStreams(options);
            return(container);
        }
        /// <summary>
        /// Creates a new video stream for the specified <see cref="OutputContainer"/>.
        /// </summary>
        /// <param name="container">The media container.</param>
        /// <param name="config">The stream settings.</param>
        /// <returns>The new video stream.</returns>
        public static OutputStream <VideoFrame> CreateVideo(OutputContainer container, VideoEncoderSettings config)
        {
            var codecId = config.Codec == VideoCodec.Default ? container.Pointer->oformat->video_codec : (AVCodecID)config.Codec;

            if (codecId == AVCodecID.AV_CODEC_ID_NONE)
            {
                throw new InvalidOperationException("The media container doesn't support video!");
            }

            var codec = ffmpeg.avcodec_find_encoder(codecId);

            if (codec == null)
            {
                throw new InvalidOperationException($"Cannot find an encoder with the {codecId}!");
            }

            if (codec->type != AVMediaType.AVMEDIA_TYPE_VIDEO)
            {
                throw new InvalidOperationException($"The {codecId} encoder doesn't support video!");
            }

            var videoStream = ffmpeg.avformat_new_stream(container.Pointer, codec);

            videoStream->time_base    = config.TimeBase;
            videoStream->r_frame_rate = config.FramerateRational;

            var codecContext = videoStream->codec;

            codecContext->codec_id   = codecId;
            codecContext->codec_type = AVMediaType.AVMEDIA_TYPE_VIDEO;

            codecContext->width  = config.VideoWidth;
            codecContext->height = config.VideoHeight;

            codecContext->time_base = videoStream->time_base;
            codecContext->framerate = videoStream->r_frame_rate;
            codecContext->gop_size  = config.KeyframeRate;
            codecContext->pix_fmt   = (AVPixelFormat)config.VideoFormat;

            if ((container.Pointer->oformat->flags & ffmpeg.AVFMT_GLOBALHEADER) != 0)
            {
                codecContext->flags |= ffmpeg.AV_CODEC_FLAG_GLOBAL_HEADER;
            }

            var dict = new FFDictionary(config.CodecOptions);

            if (config.CRF.HasValue && config.Codec.IsMatch(VideoCodec.H264, VideoCodec.H265, VideoCodec.VP9, VideoCodec.VP8))
            {
                dict["crf"] = config.CRF.Value.ToString();
            }
            else
            {
                codecContext->bit_rate = config.Bitrate;
            }

            if (config.Codec.IsMatch(VideoCodec.H264, VideoCodec.H265))
            {
                dict["preset"] = config.EncoderPreset.GetDescription();
            }

            var ptr = dict.Pointer;

            ffmpeg.avcodec_open2(codecContext, codec, &ptr);

            dict.Update(ptr);

            return(new OutputStream <VideoFrame>(videoStream, container));
        }