2016-01-05 3 views
1

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?

+0

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

+0

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

+0

probablement votre encodeur crée IPPPPPP ..... et après env. 5 min la seconde I Cadre apparaît. – incBrain

Répondre

0

J'ai résolu ces problèmes en utilisant rtp sur tcp au lieu de rtp sur udp.