Beispiel #1
0
        // sets up libavformat state: creates the AVFormatContext, the frames, etc. to start decoding, but does not actually start the decodingLoop
        private void prepareDecoding()
        {
            const int context_buffer_size = 4096;

            // the first call to FFmpeg will throw an exception if the libraries cannot be found
            // this will be safely handled in StartDecoding()
            var fcPtr = ffmpeg.avformat_alloc_context();

            formatContext        = fcPtr;
            contextBuffer        = (byte *)ffmpeg.av_malloc(context_buffer_size);
            managedContextBuffer = new byte[context_buffer_size];
            readPacketCallback   = readPacket;
            seekCallback         = streamSeekCallbacks;
            formatContext->pb    = ffmpeg.avio_alloc_context(contextBuffer, context_buffer_size, 0, (void *)handle.Handle, readPacketCallback, null, seekCallback);

            int openInputResult = ffmpeg.avformat_open_input(&fcPtr, "dummy", null, null);

            inputOpened = openInputResult >= 0;
            if (!inputOpened)
            {
                throw new InvalidOperationException($"Error opening file or stream: {getErrorMessage(openInputResult)}");
            }

            int findStreamInfoResult = ffmpeg.avformat_find_stream_info(formatContext, null);

            if (findStreamInfoResult < 0)
            {
                throw new InvalidOperationException($"Error finding stream info: {getErrorMessage(findStreamInfoResult)}");
            }

            var nStreams = formatContext->nb_streams;

            for (var i = 0; i < nStreams; ++i)
            {
                stream = formatContext->streams[i];

                codecParams = *stream->codecpar;

                if (codecParams.codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO)
                {
                    duration = stream->duration <= 0 ? formatContext->duration : stream->duration;

                    timeBaseInSeconds = stream->time_base.GetValue();
                    var codecPtr = ffmpeg.avcodec_find_decoder(codecParams.codec_id);
                    if (codecPtr == null)
                    {
                        throw new InvalidOperationException($"Couldn't find codec with id: {codecParams.codec_id}");
                    }

                    int openCodecResult = ffmpeg.avcodec_open2(stream->codec, codecPtr, null);
                    if (openCodecResult < 0)
                    {
                        throw new InvalidOperationException($"Error trying to open codec with id {codecParams.codec_id}: {getErrorMessage(openCodecResult)}");
                    }

                    break;
                }
            }

            prepareFilters();
        }
Beispiel #2
0
        private void recreateCodecContext()
        {
            if (stream == null)
            {
                return;
            }

            var  codecParams    = *stream->codecpar;
            bool openSuccessful = false;

            foreach (var(decoder, hwDeviceType) in GetAvailableDecoders(formatContext->iformat, codecParams.codec_id, TargetHardwareVideoDecoders.Value))
            {
                // free context in case it was allocated in a previous iteration or recreate call.
                if (codecContext != null)
                {
                    fixed(AVCodecContext **ptr = &codecContext)
                    ffmpeg.avcodec_free_context(ptr);
                }

                codecContext = ffmpeg.avcodec_alloc_context3(decoder.Pointer);
                codecContext->pkt_timebase = stream->time_base;

                if (codecContext == null)
                {
                    Logger.Log($"Couldn't allocate codec context. Codec: {decoder.Name}");
                    continue;
                }

                int paramCopyResult = ffmpeg.avcodec_parameters_to_context(codecContext, &codecParams);

                if (paramCopyResult < 0)
                {
                    Logger.Log($"Couldn't copy codec parameters from {decoder.Name}: {getErrorMessage(paramCopyResult)}");
                    continue;
                }

                // initialize hardware decode context.
                if (hwDeviceType != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
                {
                    int hwDeviceCreateResult = ffmpeg.av_hwdevice_ctx_create(&codecContext->hw_device_ctx, hwDeviceType, null, null, 0);

                    if (hwDeviceCreateResult < 0)
                    {
                        Logger.Log($"Couldn't create hardware video decoder context {hwDeviceType} for codec {decoder.Name}: {getErrorMessage(hwDeviceCreateResult)}");
                        continue;
                    }

                    Logger.Log($"Successfully opened hardware video decoder context {hwDeviceType} for codec {decoder.Name}");
                }

                int openCodecResult = ffmpeg.avcodec_open2(codecContext, decoder.Pointer, null);

                if (openCodecResult < 0)
                {
                    Logger.Log($"Error trying to open {decoder.Name} codec: {getErrorMessage(openCodecResult)}");
                    continue;
                }

                Logger.Log($"Successfully initialized decoder: {decoder.Name}");

                openSuccessful = true;
                break;
            }

            if (!openSuccessful)
            {
                throw new InvalidOperationException("No usable decoder found");
            }
        }