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); } }
public void SetAudioHandler(OnAudioFrame onAudioFrame) { this.onAudioFrame = onAudioFrame; ZegoExpressEngineImpl.SetAudioHandler(this, onAudioFrame); }