nyanmisaka / ffmpeg-rockchip

FFmpeg with async and zero-copy Rockchip MPP & RGA support
Other
325 stars 47 forks source link

`avcodec_receive_packet` return AVERROR(EAGAIN),cannot receive encoded packets continuously #70

Closed MUCHWAY closed 3 weeks ago

MUCHWAY commented 1 month ago

avcodec_receive_packet cannot receive encoded packets continuously. The current thinking is that 'h264_rkmpp' is used as decoder and encoder. The frame rate of video source is 25fps. avcodec_receive_packet does not receive packets in every cycle. Packets are always received after an interval of one cycle. My key code is:

    printf("read pkt from stream\n");
    int ret = -1;
    uint32_t read_data_time = 0;
    uint32_t decoder_time = 0;
    uint32_t encoder_time = 0;
    int data_size = 0;  

    ret = av_read_frame(g_iFmtCtx, g_iDecPkt);
    if(ret < 0){
        printf("no any data\n");
        return -1;
    }

    if(g_iDecPkt->stream_index != g_iStreamIndx){
        printf("it is not video stream\n");
        return -1;
    }
    printf("g_iDecPkt size %d\n", g_iDecPkt->size);

    GetTimeMs(&read_data_time);
    printf("read_data_time ------------>%d ms\n", read_data_time - g_LoopStart);

    printf("send pkt to decoder\n");
    ret = avcodec_send_packet(g_iDecCtx, g_iDecPkt);
    if (ret != 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
        return -1;
    }
    av_packet_unref(g_iDecPkt);

    printf("read frame from decoder\n");
    while(1){
        ret = avcodec_receive_frame(g_iDecCtx, g_Frame);
        if(ret == AVERROR(EAGAIN)){
            printf("need input more packet\n");
            break;
        }else if(ret == AVERROR_EOF){
            return -1;
        }else if (ret < 0 ){ 
            printf("Error decoding frame! \n");
            return - 1;
        }

      ret = av_hwframe_transfer_data(g_newFrame, g_Frame, 0);
      if (ret < 0) {
      fprintf(stderr, "Error transferring the data to system memory\n");
             return -1;
      }

       printf("send frame to encoder\n");
       ret = avcodec_send_frame(g_oEncCtx, g_newFrame);
        if (ret < 0) {
            fprintf(stderr, "Error sending a frame to the encoder: %s\n", av_err2str(ret));
            return -1;
        }
    }

    GetTimeMs(&decoder_time);
    printf("decoder_time -------------->%d ms\n", decoder_time - read_data_time);

    printf("read pkt from encoder\n");
    while(g_oEncCtx != NULL){
        ret = avcodec_receive_packet(g_oEncCtx, g_oEncPkt);
        printf("g_oEncPkt size %d\n", g_oEncPkt->size);
        if (ret == AVERROR(EAGAIN)){
            printf("need input more frame\n");
            break;
        }else if(ret == AVERROR_EOF){
            return -1;
        }else if(ret < 0) {
            printf("Error encoding ! \n");
            return -1;
        }

        if(g_oEncPkt->size > 0){
            memcpy((dataBuffer + data_size), g_oEncPkt->data, g_oEncPkt->size);
            data_size += g_oEncPkt->size;
        }
        av_packet_unref(g_oEncPkt);
    }

    av_packet_unref(g_oEncPkt);

    GetTimeMs(&encoder_time);
    printf("encoder_time -------------->%d ms\n", encoder_time - decoder_time);

    printf("get size %d\n", data_size);
    return data_size;

When code is run, output information via printf:

read pkt from stream
g_iDecPkt size 16414
read_data_time ------------>1 ms
send pkt to decoder
read frame from decoder
send frame to encoder
send frame to encoder
need input more pkt
decoder_time -------------->25 ms
read pkt from encoder
g_oEncPkt size 5547
g_oEncPkt size 7990
g_oEncPkt size 0
need input more frame
encoder_time -------------->17 ms
get size 13537
loop_time ----------------->44 ms

read pkt from stream
g_iDecPkt size 16937
read_data_time ------------>1 ms
send pkt to decoder
read frame from decoder
need input more pkt
decoder_time -------------->0 ms
read pkt from encoder
g_oEncPkt size 0
need input more frame
encoder_time -------------->1 ms
get size 0
loop_time ----------------->40 ms

read pkt from stream
g_iDecPkt size 16725
read_data_time ------------>1 ms
send pkt to decoder
read frame from decoder
send frame to encoder
send frame to encoder
need input more pkt
decoder_time -------------->27 ms
read pkt from encoder
g_oEncPkt size 6821
g_oEncPkt size 6437
g_oEncPkt size 0
need input more frame
encoder_time -------------->16 ms
get size 13258
loop_time ----------------->44 ms

read pkt from stream
g_iDecPkt size 15912
read_data_time ------------>1 ms
send pkt to decoder
read frame from decoder
need input more pkt
decoder_time -------------->1 ms
read pkt from encoder
g_oEncPkt size 0
need input more frame
encoder_time -------------->0 ms
get size 0
loop_time ----------------->40 ms

avcodec_receive_packet return AVERROR(EAGAIN),I try to send more packet to endocer, but there was no improvement.

MUCHWAY commented 1 month ago

When I use h264_rkmpp only as an encoder, not as a decoder, the same program runs as follows:

read pkt from stream
g_iDecPkt size 20027
read_data_time ------------>1 ms
send pkt to decoder
read frame from decoder
send frame to encoder
need input more pkt
decoder_time -------------->49 ms
read pkt from encoder
g_oEncPkt size 2463
g_oEncPkt size 0
need input more frame
encoder_time -------------->0 ms
get size 2463
loop_time ----------------->50 ms

read pkt from stream
g_iDecPkt size 23244
read_data_time ------------>2 ms
send pkt to decoder
read frame from decoder
send frame to encoder
need input more pkt
decoder_time -------------->59 ms
read pkt from encoder
g_oEncPkt size 2813
g_oEncPkt size 0
need input more frame
encoder_time -------------->0 ms
get size 2813
loop_time ----------------->62 ms

read pkt from stream
g_iDecPkt size 12861
read_data_time ------------>1 ms
send pkt to decoder
read frame from decoder
send frame to encoder
need input more pkt
decoder_time -------------->54 ms
read pkt from encoder
g_oEncPkt size 2369
g_oEncPkt size 0
need input more frame
encoder_time -------------->0 ms
get size 2369
loop_time ----------------->56 ms
nyanmisaka commented 1 month ago

Please use the ffmpeg command line to reproduce the issue.

nyanmisaka commented 3 weeks ago

Use -flags +low_delay if you need one-input-one-output encoder mode.