Beispiel #1
0
        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);
        }
Beispiel #2
0
        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}]")}");
            }
        }