private unsafe void RunDecodeLoop()
        {
            AVPacket *pkt     = ffmpeg.av_packet_alloc();
            AVFrame * avFrame = ffmpeg.av_frame_alloc();

            int eagain = ffmpeg.AVERROR(ffmpeg.EAGAIN);
            int error;

            bool canContinue  = true;
            bool managePacket = true;

            double firts_dpts = 0;

            double original_dpts = 0;

            try
            {
                // Decode loop.
                pkt = ffmpeg.av_packet_alloc();

Repeat:

                DateTime startTime = DateTime.Now;

                while (!_isClosed && !_isPaused && canContinue)
                {
                    error = ffmpeg.av_read_frame(_fmtCtx, pkt);
                    if (error < 0)
                    {
                        managePacket = false;
                        if (error == eagain)
                        {
                            ffmpeg.av_packet_unref(pkt);
                        }
                        else
                        {
                            canContinue = false;
                        }
                    }
                    else
                    {
                        managePacket = true;
                    }

                    if (managePacket)
                    {
                        if (pkt->stream_index == _audioStreamIndex)
                        {
                            ffmpeg.avcodec_send_packet(_audDecCtx, pkt).ThrowExceptionIfError();
                            int recvRes = ffmpeg.avcodec_receive_frame(_audDecCtx, avFrame);
                            while (recvRes >= 0)
                            {
                                OnAudioFrame?.Invoke(ref *avFrame);


                                if (!_isMicrophone)
                                {
                                    double dpts = 0;
                                    if (avFrame->pts != ffmpeg.AV_NOPTS_VALUE)
                                    {
                                        dpts          = _audioTimebase * avFrame->pts;
                                        original_dpts = dpts;

                                        if (firts_dpts == 0)
                                        {
                                            firts_dpts = dpts;
                                        }

                                        dpts -= firts_dpts;
                                    }
                                    int sleep = (int)(dpts * 1000 - DateTime.Now.Subtract(startTime).TotalMilliseconds);
                                    Console.WriteLine($"sleep {sleep} {Math.Min(_maxAudioFrameSpace, sleep)} - firts_dpts:{firts_dpts} - dpts:{dpts} - original_dpts:{original_dpts}");


                                    if (sleep > Helper.MIN_SLEEP_MILLISECONDS)
                                    {
                                        ffmpeg.av_usleep((uint)(Math.Min(_maxAudioFrameSpace, sleep) * 1000));
                                    }
                                }

                                recvRes = ffmpeg.avcodec_receive_frame(_audDecCtx, avFrame);
                            }

                            if (recvRes < 0 && recvRes != ffmpeg.AVERROR(ffmpeg.EAGAIN))
                            {
                                recvRes.ThrowExceptionIfError();
                            }
                        }

                        ffmpeg.av_packet_unref(pkt);
                    }
                }

                if (_isPaused)
                {
                    ((int)ffmpeg.avio_seek(_fmtCtx->pb, 0, ffmpeg.AVIO_SEEKABLE_NORMAL)).ThrowExceptionIfError();

                    ffmpeg.avformat_seek_file(_fmtCtx, _audioStreamIndex, 0, 0, _fmtCtx->streams[_audioStreamIndex]->duration, 0).ThrowExceptionIfError();
                }
                else
                {
                    logger.LogDebug($"FFmpeg end of file for source {_sourceUrl}.");

                    if (!_isClosed && _repeat)
                    {
                        ((int)ffmpeg.avio_seek(_fmtCtx->pb, 0, ffmpeg.AVIO_SEEKABLE_NORMAL)).ThrowExceptionIfError();

                        ffmpeg.avformat_seek_file(_fmtCtx, _audioStreamIndex, 0, 0, _fmtCtx->streams[_audioStreamIndex]->duration, 0).ThrowExceptionIfError();

                        canContinue = true;
                        goto Repeat;
                    }
                    else
                    {
                        OnEndOfFile?.Invoke();
                    }
                }
            }
            finally
            {
                ffmpeg.av_frame_unref(avFrame);
                ffmpeg.av_free(avFrame);

                ffmpeg.av_packet_unref(pkt);
                ffmpeg.av_free(pkt);
            }
        }
Ejemplo n.º 2
0
 public void SetAudioHandler(OnAudioFrame onAudioFrame)
 {
     this.onAudioFrame = onAudioFrame;
     ZegoExpressEngineImpl.SetAudioHandler(this, onAudioFrame);
 }