bool RtspStreamWorker::openCodec(AVStream *stream, AVDictionary *options)
{
    startInterruptableOperation(5);
    AVCodec *codec = avcodec_find_decoder(stream->codec->codec_id);

    AVDictionary *optionsCopy = 0;
    av_dict_copy(&optionsCopy, options, 0);
    startInterruptableOperation(5);
    int errorCode = avcodec_open2(stream->codec, codec, &optionsCopy);
    av_dict_free(&optionsCopy);

    return 0 == errorCode;
}
AVFrame * RtspStreamWorker::extractVideoFrame(AVPacket &packet)
{
    AVFrame *frame = av_frame_alloc();
    startInterruptableOperation(5);

    int pictureAvailable;
    int re = avcodec_decode_video2(m_ctx->streams[m_videoStreamIndex]->codec, frame, &pictureAvailable, &packet);
    if (re == 0) {
        return 0;
    }

    if (re < 0)
    {
        m_decodeErrorsCnt++;

        if (m_decodeErrorsCnt >= maxDecodeErrors)
        {
            emit fatalError(QString::fromLatin1("Decoding error: %1").arg(errorMessageFromCode(re)));
        }
        av_free(frame);
        return 0;
    }

    m_decodeErrorsCnt = 0; //reset error counter if avcodec_decode_video2() call was successful
    packet.size -= re;
    packet.data += re;

    if (!pictureAvailable)
    {
        av_free(frame);
        return 0;
    }

    return frame;
}
AVFrame * RtspStreamWorker::extractAudioFrame(AVPacket &packet)
{
    AVFrame *frame = av_frame_alloc();
    startInterruptableOperation(5);

    int frameAvailable;

    int ret = avcodec_decode_audio4(m_ctx->streams[m_audioStreamIndex]->codec, frame, &frameAvailable, &packet);

    if (ret == 0)
        return 0;

    if (ret < 0)
    {
        av_free(frame);
        return 0;
    }

    packet.size -= ret;
    packet.data += ret;

    if (!frameAvailable)
    {
        av_free(frame);
        return 0;
    }

    return frame;
}
AVFrame * RtspStreamWorker::extractFrame(AVPacket &packet, bool *breakLoop)
{
    *breakLoop = false;

    AVFrame *frame = avcodec_alloc_frame();
    startInterruptableOperation(5);

    int pictureAvailable;
    int re = avcodec_decode_video2(m_ctx->streams[0]->codec, frame, &pictureAvailable, &packet);
    if (re == 0) {
        *breakLoop = true;
        return 0;
    }

    if (re < 0)
    {
        emit fatalError(QString::fromLatin1("Decoding error: %1").arg(errorMessageFromCode(re)));
        av_free(frame);
        *breakLoop = true;
        return 0;
    }

    packet.size -= re;
    packet.data += re;

    if (!pictureAvailable)
    {
        av_free(frame);
        return 0;
    }

    return frame;
}
RtspStreamWorker::~RtspStreamWorker()
{
    if (!m_ctx)
        return;

    for (unsigned int i = 0; i < m_ctx->nb_streams; ++i)
    {
        avcodec_close(m_ctx->streams[i]->codec);
    }

    startInterruptableOperation(5);
    avformat_close_input(&m_ctx);
}
bool RtspStreamWorker::findStreamInfo(AVFormatContext* context, AVDictionary* options)
{
    AVDictionary **streamOptions = createStreamsOptions(context, options);
    startInterruptableOperation(20);
    int errorCode = avformat_find_stream_info(context, streamOptions);
    destroyStreamOptions(context, streamOptions);

    if (errorCode < 0)
    {
        emit fatalError(QString::fromLatin1("Find stream error: %1").arg(errorMessageFromCode(errorCode)));
        return false;
    }

    return true;
}
bool RtspStreamWorker::openInput(AVFormatContext **context, AVDictionary *options)
{
    AVDictionary *optionsCopy = 0;
    av_dict_copy(&optionsCopy, options, 0);
    startInterruptableOperation(20);
    int errorCode = avformat_open_input(context, qPrintable(m_url.toString()), NULL, &optionsCopy);
    av_dict_free(&optionsCopy);

    if (errorCode < 0)
    {
        emit fatalError(QString::fromLatin1("Open error: %1").arg(errorMessageFromCode(errorCode)));
        return false;
    }

    return true;
}
AVPacket RtspStreamWorker::readPacket(bool *ok)
{
    if (ok)
        *ok = true;

    AVPacket packet;
    startInterruptableOperation(30);
    int re = av_read_frame(m_ctx, &packet);
    if (0 == re)
        return packet;

    emit fatalError(QString::fromLatin1("Reading error: %1").arg(errorMessageFromCode(re)));
    av_packet_unref(&packet);

    if (ok)
        *ok = false;
    return packet;
}
void RtspStreamWorker::processVideoFrame(struct AVFrame *rawFrame)
{
    Q_ASSERT(m_frameFormatter);
    startInterruptableOperation(5);
    m_frameQueue->enqueue(m_frameFormatter->formatFrame(rawFrame));
}