ffmpeg는 프레임 손실 문제를 해결합니다. 디코더에는 여전히 몇 개의 데이터 프레임이 캐시되어 있으므로 제거해야 합니다.

머리말
       

최근에 ffmpeg를 이용하여 영상을 분석하는 방법을 배우고 있습니다. 인터넷에서 검색하는 방법도 비슷합니다. 디코딩 함수인 avcodec_send_packet과 avcodec_receive_frame에 대해 직접 이야기합니다. 이 둘은 함께 있어서 동시에 나타나야 합니다. 영상 파일을 읽어요. 추출된 패킷을 videoQueue 또는 audioQueue에 넣은 다음 SDL을 사용하여 videoThread를 생성하여 비디오 큐에서 지속적으로 패킷을 꺼내 디코더로 보냅니다. 즉, avcodec_send_packet을 사용하여 패킷을 디코더를 사용하고 avcodec_receive_frame을 사용하여 ffmpeg에서 프레임을 구문 분석합니다. 꺼내지만 진행률 표시줄을 통해 현재 프레임의 시간을 보거나 디코딩된 프레임->pt를 직접 인쇄하면 끝에는 항상 몇 프레임이 적습니다. , 매우 우울하다

1. 프레임 손실 이유
디코더 내부에는 버퍼 큐가 있습니다. 처음에는 먼저 몇 프레임의 데이터를 저장한 다음 유효한 프레임을 출력하기 시작하므로 결국에는 여전히 몇 프레임의 데이터가 남아 있습니다. 영상의 크기에 따라 디코더에 아직 프레임이 남아있는데, 패킷 수가 동일하지 않아 마지막에 출력되지 않는 프레임이 여전히 몇 개 남아 있어 프레임 손실이 발생합니다.

2. 해결책
첫 번째 아이디어는 프레임 손실을 해결하는 방법을 인터넷에서 검색하는 것이지만 소스 코드도 거의 없고 특히 ffmpeg의 avcodec_send_packet 및 avcodec_receive_frame의 프레임 손실 솔루션이 적기 때문에 다음으로 방향을 돌렸습니다. 공식 문서에서 마침내 발견되었습니다. 약간의 단서, 다음 그림은 avcode.h에서 발견됩니다. avcode.h는 이 두 함수에 의해 선언된 헤더 파일이기도 합니다.

위의 내용은 필요에 따라 또는 성능 향상을 위해 코덱이 마지막에 몇 개의 데이터 프레임을 캐시할 수 있으며 코덱을 새로 고쳐야 함을 보여주며 아이디어도 제공합니다.

1. 빈 패킷을 avcodec_send_packet으로 보냅니다.
위의 공식 문서에서 제시한 아이디어처럼 빈 패킷을 디코더로 보내야 합니다.코드는 다음과 같습니다.

packet->data = nullptr;
packet->size = 0;
avcodec_send_packet(pVideoCodecCtx, packet);


2. avcodec_receive_frame을 호출하여 빈 패킷을 보낸 후
avcodec_receive_frame을 호출하여 avcodec_receive_frame이 AVERROR_EOF를 반환할 때까지 디코딩된 프레임을 꺼냅니다. 코드는 다음과 같습니다.

/**队列里取数据**/
        if (packet_queue_get(&pVideosState->videoQueue, packet, 0) <= 0)
        {
 
            if (pVideosState->readFinished)
            {
                /**队列里面没有数据了且读取完毕了**/
                while(1)
                {
                    packet->data = nullptr;
                    packet->size = 0;
                    avcodec_send_packet(pVideoCodecCtx, packet);
                    
                    ret = avcodec_receive_frame(pVideoCodecCtx, pFrame);
                    if(ret == AVERROR_EOF)
                        break;
                    
                    //进行你所需的一系列操作
                }
                //这个循环跳出后就全部取出解码器缓存的数据了
            }

추천

출처blog.csdn.net/xionglifei2014/article/details/124951833