J'ai un ip de caméras sur le réseau local.Je reçois un flux vidéo avec la bibliothèque live555 (j'ai pris testRtspClient comme base) et décode les trames avec ffmpeg (avcodec_decode_video2). Tout fonctionne parfaitement. Les problèmes commencent lorsque j'essaie de décoder un flux d'Internet.ffmpeg ne décode pas certains flux h264
Le premier problème - certains paquets perdus, donc des défauts apparaissent. Mais ce n'est pas un problème. Problème - après l'arrêt et le démarrage du flux vidéo, il est nécessaire d'attendre environ 5 minutes de streaming avant que ffmpeg ne puisse décoder quelque chose de la même caméra IP. Si les paquets ne sont pas perdus alors tout va bien.
Le deuxième problème - il y a caméra qui envoie la vidéo avec la résolution 2048х1538. Le cadre d'une telle résolution est envoyé par plusieurs paquets. LIVE555 apporte normalement ensemble eux, mais lorsque le cadre est transféré au décodeur, le décodeur retourne la longueur du paquet, mais se trame toujours 0.
Voici quelques mon code:
#define RECEIVE_BUFFER_SIZE 1000000
AVCodecContext* avCodecContext; //definition
AVFrame *frame; //definition
...
//init code
_fReceiveBuffer = new uint8_t[RECEIVE_BUFFER_SIZE+512]; //buffer to receive frame
ZeroMemory(_fReceiveBuffer, RECEIVE_BUFFER_SIZE + 512); //zeros
_bufferSize = RECEIVE_BUFFER_SIZE * sizeof(uint8_t); //buffer size
static const uint8_t startCode[4] = { 0x00, 0x00, 0x00, 0x01 }; //this is for 0 0 0 1
//before frame will transfer to decoder
memcpy(_fReceiveBuffer, (void*)startCode, sizeof(uint8_t)* 4);
_fReceiveBuffer += sizeof(sizeof(uint8_t)* 4);
_bufferSize -= sizeof(sizeof(uint8_t)* 4);
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264); //find codec
avCodecContext = avcodec_alloc_context3(codec);
avCodecContext->flags |= AV_PKT_FLAG_KEY;
avcodec_open2(avCodecContext, codec, NULL);
frame = av_frame_alloc();
//frame
void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned durationInMicroseconds) {
if (strcmp(fSubsession.codecName(), "H264") == 0)
{
//code from onvif device manager
static const uint8_t startCode3[] = { 0x00, 0x00, 0x01 };
static const uint8_t startCode4[] = { 0x00, 0x00, 0x00, 0x01 };
auto correctedFrameSize = frameSize;
auto correctedBufferPtr = fPlObj->_fReceiveBuffer;
if (frameSize < sizeof(startCode4) || memcmp(startCode4, correctedBufferPtr, sizeof(startCode4)) != 0){
if (frameSize < sizeof(startCode3) || memcmp(startCode3, correctedBufferPtr, sizeof(startCode3)) != 0){
correctedFrameSize += sizeof(uint8_t)* 4;
correctedBufferPtr -= sizeof(uint8_t)* 4;
}
}
ProcessFrame(correctedBufferPtr, correctedFrameSize, presentationTime, durationInMicroseconds);
}
continuePlaying();
}
void DummySink::ProcessFrame(unsigned char* framePtr, int frameSize, struct timeval presentationTime, unsigned duration) {
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = framePtr;
avpkt.size = frameSize;
while (avpkt.size > 0) {
int got_frame = 0;
int len = avcodec_decode_video2(avCodecContext, frame, &got_frame, &avpkt);
if (len < 0) {
//TODO: log error
return;
}
else if (got_frame == 0)
{
//I tried this code, bacause "codecs which have the AV_CODEC_CAP_DELAY capability set have a delay between input and output"
//but it didn't help
/*AVPacket emptyPacket;
av_init_packet(&emptyPacket);
emptyPacket.data = NULL;
emptyPacket.size = 0;
emptyPacket.stream_index = avpkt.stream_index;
len = avcodec_decode_video2(avCodecContext, frame, &got_frame, &emptyPacket);
if (got_frame == 1) goto next;*/
return;
}
next:
//... here code for view with DirectDraw - everithing ok with it
avpkt.size -= len;
avpkt.data += len;
}
}
Je alsa essayé d'envoyer cadre au décodeur avec l'information de sps et de pps:
0 0 0 1 sps 0 0 0 1 pps 0 0 0 1 frame
mais ce n'est pas aide.
intéressant que avcodec_decode_video2 ne renvoie pas de trame avec le second problème (retourner toutes les tailles de trame), mais la largeur et la hauteur dans avCodecContext sont définies correctement. Je ne peux pas comprendre pourquoi il ne retourne pas le cadre.
Quelqu'un peut-il aider avec ces problèmes?
combien d'images avez-vous observé ne renvoyant aucune image dans le deuxième problème? Conformément à H264, il ne s'agit pas nécessairement de donner la trame pour l'affichage, immédiatement après le décodage. Les commandes de décodage et d'affichage sont différentes dans H264. Donc, je vous suggère de vérifier pour plus de 16 images en général pour trouver un cadre pour l'affichage – ARK
Merci pour l'information. Pendant le test, le deuxième problème était le résultat du premier. Si je démarre le programme la première fois - ok, la deuxième fois - beaucoup plus de 16 images reçues et rien décodage. Mais alors je décide d'utiliser rtp sur tcp au lieu de rtp sur udp - les problèmes disparaissent. Si rtp utilise udp alors environ 1 paquets dans 50-100 perdu, mais je ne peux pas comprendre pourquoi il est si critique lorsque je cours le programme deuxième fois et plus. – Andrey
probablement votre encodeur crée IPPPPPP ..... et après env. 5 min la seconde I Cadre apparaît. – incBrain