public long GetVideoFrame() { int ret; long firstTs = -1; while (interrupt != 1) { AVPacket *pkt = av_packet_alloc(); ret = av_read_frame(demuxer.fmtCtx, pkt); if (ret != 0) { return(-1); } if (!demuxer.enabledStreams.Contains(pkt->stream_index)) { av_packet_free(&pkt); continue; } switch (demuxer.fmtCtx->streams[pkt->stream_index]->codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: aDecoder.packets.Enqueue((IntPtr)pkt); break; case AVMEDIA_TYPE_VIDEO: lock (device) ret = avcodec_send_packet(vDecoder.codecCtx, pkt); av_packet_free(&pkt); if (ret != 0) { return(-1); } while (interrupt != 1) { AVFrame *frame = av_frame_alloc(); lock (device) ret = avcodec_receive_frame(vDecoder.codecCtx, frame); if (ret == 0) { MediaFrame mFrame = new MediaFrame(); mFrame.pts = frame->best_effort_timestamp == AV_NOPTS_VALUE ? frame->pts : frame->best_effort_timestamp; mFrame.timestamp = ((long)(mFrame.pts * vDecoder.info.Timebase) - demuxer.streams[vDecoder.st->index].StartTime) + opt.audio.LatencyTicks; if (mFrame.pts == AV_NOPTS_VALUE) { av_frame_free(&frame); continue; } if (firstTs == -1) { if (vDecoder.hwAccelSuccess && frame->hw_frames_ctx == null) { vDecoder.hwAccelSuccess = false; } firstTs = mFrame.timestamp; } if (MediaFrame.ProcessVideoFrame(vDecoder, mFrame, frame) != 0) { mFrame = null; } if (mFrame != null) { vDecoder.frames.Enqueue(mFrame); } //Log(Utils.TicksToTime((long)(mFrame.pts * avs.streams[video.st->index].timebase))); av_frame_free(&frame); continue; } av_frame_free(&frame); break; } break; case AVMEDIA_TYPE_SUBTITLE: sDecoder.packets.Enqueue((IntPtr)pkt); break; default: av_packet_free(&pkt); break; } if (firstTs != -1) { break; } } return(firstTs); }
public void Decode() { //int xf = 0; AVPacket *pkt; while (true) { if (status != Status.END) { status = Status.READY; } decodeARE.Reset(); decodeARE.WaitOne(); status = Status.PLAY; forcePause = false; bool shouldStop = false; int allowedErrors = decCtx.opt.demuxer.MaxErrors; int ret = -1; Log("Started"); // Wait for demuxer to come up if (demuxer.status == Status.READY) { demuxer.demuxARE.Set(); while (!demuxer.isPlaying && demuxer.status != Status.END) { Thread.Sleep(1); } } while (true) { // No Packets || Max Frames Brakes if (packets.Count == 0 || (type == Type.Audio && frames.Count > decCtx.opt.audio.MaxDecodedFrames) || (type == Type.Video && frames.Count > decCtx.opt.video.MaxDecodedFrames) || (type == Type.Subs && frames.Count > decCtx.opt.subs.MaxDecodedFrames)) { shouldStop = false; //isWaiting = true; do { if (!decCtx.isPlaying || forcePause) // Proper Pause { Log("Pausing"); shouldStop = true; break; } else if (packets.Count == 0 && demuxer.status == Status.END) // Drain { Log("Draining"); break; } //else if (packets.Count == 0 && (!demuxer.isPlaying || demuxer.isWaiting)) // No reason to run else if (packets.Count == 0 && (!demuxer.isPlaying || ((!isEmbedded || type == Type.Video) && demuxer.isWaiting))) // No reason to run { Log("Exhausted " + isPlaying); shouldStop = true; break; } Thread.Sleep(10); } while (packets.Count == 0 || (type == Type.Audio && frames.Count > decCtx.opt.audio.MaxDecodedFrames) || (type == Type.Video && frames.Count > decCtx.opt.video.MaxDecodedFrames) || (type == Type.Subs && frames.Count > decCtx.opt.subs.MaxDecodedFrames)); //isWaiting = false; if (shouldStop) { break; } } if (packets.Count == 0 && demuxer.status == Status.END) { if (type == Type.Video) { // Check case pause while draining Log("Draining..."); pkt = null; } else { status = Status.END; Log("EOF"); break; } } else { packets.TryDequeue(out IntPtr pktPtr); pkt = (AVPacket *)pktPtr; if (type == Type.Subs) { MediaFrame mFrame = new MediaFrame(); mFrame.pts = pkt->pts; mFrame.timestamp = (long)((mFrame.pts * info.Timebase)) + opt.audio.LatencyTicks + opt.subs.DelayTicks; //Log(Utils.TicksToTime((long)(mFrame.pts * demuxer.streams[st->index].timebase)) + " | pts -> " + mFrame.pts); //xf++; if (mFrame.pts == AV_NOPTS_VALUE) { av_packet_free(&pkt); continue; } int gotFrame = 0; AVSubtitle sub = new AVSubtitle(); // drain mode todo // pkt->data set to NULL && pkt->size = 0 until it stops returning subtitles ret = avcodec_decode_subtitle2(codecCtx, &sub, &gotFrame, pkt); if (ret < 0) { allowedErrors--; Log($"[ERROR-2] {Utils.ErrorCodeToMsg(ret)} ({ret})"); if (allowedErrors == 0) { Log("[ERROR-0] Too many errors!"); break; } continue; } if (gotFrame < 1 || sub.num_rects < 1) { continue; } MediaFrame.ProcessSubsFrame(this, mFrame, &sub); frames.Enqueue(mFrame); avsubtitle_free(&sub); av_packet_free(&pkt); continue; } } lock (demuxer.decCtx.device) ret = avcodec_send_packet(codecCtx, pkt); if (ret != 0 && ret != AVERROR(EAGAIN)) { if (ret == AVERROR_EOF) { status = Status.END; Log("EOF"); break; } else //if (ret == AVERROR_INVALIDDATA) // We also get Error number -16976906 occurred { allowedErrors--; Log($"[ERROR-2] {Utils.ErrorCodeToMsg(ret)} ({ret})"); if (allowedErrors == 0) { Log("[ERROR-0] Too many errors!"); break; } continue; } } av_packet_free(&pkt); while (true) { lock (demuxer.decCtx.device) ret = avcodec_receive_frame(codecCtx, frame); if (ret == 0) { MediaFrame mFrame = new MediaFrame(); mFrame.pts = frame->best_effort_timestamp == AV_NOPTS_VALUE ? frame->pts : frame->best_effort_timestamp; if (mFrame.pts == AV_NOPTS_VALUE) { av_frame_unref(frame); continue; } //Log(Utils.TicksToTime((long)(mFrame.pts * demuxer.streams[st->index].Timebase)) + " | pts -> " + mFrame.pts); if (type == Type.Video) { if (hwAccelSuccess && frame->hw_frames_ctx == null) { hwAccelSuccess = false; } mFrame.timestamp = ((long)(mFrame.pts * info.Timebase) - demuxer.streams[st->index].StartTime) + opt.audio.LatencyTicks; if (MediaFrame.ProcessVideoFrame(this, mFrame, frame) != 0) { mFrame = null; } } else // Audio { mFrame.timestamp = ((long)(mFrame.pts * info.Timebase) - demuxer.streams[st->index].StartTime) + opt.audio.DelayTicks + (demuxer.streams[st->index].StartTime - demuxer.decCtx.vDecoder.info.StartTime); if (MediaFrame.ProcessAudioFrame(this, mFrame, frame) < 0) { mFrame = null; } } if (mFrame != null) { frames.Enqueue(mFrame); //xf++; } av_frame_unref(frame); continue; } av_frame_unref(frame); break; } if (ret == AVERROR_EOF) { status = Status.END; Log("EOF"); if (type == Type.Video && decCtx.aDecoder.status != Status.PLAY) { Log("EOF All"); decCtx.status = Status.END; } else if (type == Type.Audio && decCtx.vDecoder.status != Status.PLAY) { Log("EOF All"); decCtx.status = Status.END; } break; } if (ret != AVERROR(EAGAIN)) { Log($"[ERROR-3] {Utils.ErrorCodeToMsg(ret)} ({ret})"); break; } } Log($"Done {(allowedErrors == decCtx.opt.demuxer.MaxErrors ? "" : $"[Errors: {decCtx.opt.demuxer.MaxErrors - allowedErrors}]")}"); } }