LINUX.ORG.RU

avcodec_send_frame потокобезопасен?

 , ,


0

1

жизнь боль )

в продолжении темы Как разблокировать одновременно 2 потока?

3 потока - декодер, енкодер и снимков, декодер ждет переключения между 2 декодированными буферами по барьеру и после переключения отпускает семафоры нужных потоков енкодеров, когда их 2 все работает, только становится на 1 больше и avcodec_send_frame потока снимков начинает переодически слать ошибку -22, даже засегфолился уже ((

для примера обработчик потока снимков

int SnapshotEncode(int (*callback)(const char * topic, const uint8_t * buf, int lbuf), const char * topic)
{
    const AVCodec * pCdc = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
    if (!pCdc)
    {
        fprintf(stderr, "ERROR find snapshot encoder for '%s'\n", avcodec_get_name(AV_CODEC_ID_MJPEG));
        return -1;
    }

    struct stEncoder_t * enc = EncoderNew("snapshot");
    if (!enc) return -2;

    int rt = 0;
    AVCodecContext * pCdcCtx = avcodec_alloc_context3(pCdc);
    if (!pCdcCtx)
    {
        PrintErrorAV("alloc snapshot an encoding context", (rt = AVERROR(ENOMEM)));
        return rt;
    }

    pCdcCtx->time_base = DEFAULT_TIME_BASE;
    pCdcCtx->pix_fmt = pCdcCtxInp->pix_fmt;
    pCdcCtx->height = pCdcCtxInp->height;
    pCdcCtx->width = pCdcCtxInp->width;

    if ((rt = avcodec_open2(pCdcCtx, pCdc, NULL)))
    {
        PrintErrorAV("open snapshot encoder", rt);
        goto END;
    }

    AVPacket * pPkt = av_packet_alloc();
    if (!pPkt)
    {
        PrintErrorAV("allocate snapshot AVPacket", (rt = AVERROR(ENOMEM)));
        goto END;
    }

    EncoderRun(enc, 1);
    if ((rt = sem_wait(&enc->sem)) < 0)
        fprintf(stderr, "ERROR lock encoder semaphore: %d %s\n", errno, strerror(errno));

    if (rt)
    {
        EncoderRun(enc, 0);
        pthread_barrier_wait(&stDec.bar);
        goto END;
    }

    if ((rt = avcodec_send_frame(pCdcCtx, stEnc.pFrm)))
        PrintErrorAV("snapshot encode send", rt);
    else if ((rt = avcodec_receive_packet(pCdcCtx, pPkt)))
        PrintErrorAV("snapshot encode receive", rt);

    EncoderRun(enc, 0);
    pthread_barrier_wait(&stDec.bar);

    if (rt == 0) callback(topic, pPkt->data, pPkt->size);

    av_packet_unref(pPkt);

END:
    EncoderFree(enc);
    if (pPkt) av_packet_free(&pPkt);
    if (pCdcCtx) avcodec_free_context(&pCdcCtx);

    return rt;
}
★★★

вопщим хрен знает что там внутри делает avcodec_send_frame с уже декодированным буфером - логично же думать что он только читает??? - поэтому пришлось в потоке декодера проверять если среди енкодеров текущий не стрима, то делать для него av_frame_clone и уже когда каждый енкодер стал работать со своим AVFrame проблема ушла.

wolverin ★★★
() автор топика