Décodage d'une vidéo H264 sur RTP
Bonjour,
J'ai une Camera IP qui envoit un flux video codé en H264 sur RTP.
Je suis capable de réceptionner les paquets et de les stocker dans dans un buffer de Byte ainsi que de les décomposer pour retrouver toutes les caractéristiques du paquets (header RTP ->timestanmp, nO de séquence, SSRC, CSRC ... ; le payload RTP avec son type, mon cas est, par ailleurs, le type FU-A).
Cependant je suis incapable de de décoder ces paquets.
Avec une caméra envoyant du MPEG sur RTP, j'ai pu facilement rendre une vidéo en utilisant ffmpeg: je passais directement les paquets reçus à la fonction avcodec_decode_video() sans traitement préalable.
Avec H-264 aucun résultat ...
Du coup j'ai reconstitué moi-même les NALUS pour les transmettre au décoder comme indiqué page 33 de la RFC 3984 :
Citation:
If a decapsulated packet is an FU-A, all the fragments of the fragmented NAL unit are concatenated and passed to the decoder
Sans aucun résultat ...
Je pense que cela vient du réglage de mon décodeur. Du coup j'ai voulu utilisé le préréglage de décodage H264 de ffmpeg (VLC) pour définir le codecContext.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13
| AVCodec h264_decoder = {
"h264",
AVMEDIA_TYPE_VIDEO,
CODEC_ID_H264,
sizeof(H264Context),
ff_h264_decode_init,
NULL,
ff_h264_decode_end,
decode_frame,
/*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 | CODEC_CAP_DELAY,
.flush= flush_dpb,
.long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC /MPEG-4 part 10"),
}; |
Mais impossible de l'utiliser dans mon code ...
Bref, je suis un peu perdu d'autant plus que j'ai aussi essayé d'utiliser DirectShow en faisant un filtre source recevant mes paquets et transmettant mes NALUs reconstituées à des filtres de décodages mais sans résultats non plus.
Donc si vous avez une idée, n'hésitez pas
PS: dans vlc la vidéo marche très bien donc normalement avec ffmpeg on devrait y arriver
Décodage de vidéo H264 sur RTP avec ffmpeg (libavcodec)
J'ai un peu avancé sur la question mais le décodage global ne fonctionne pas.
Tout d'abord, j'ai récupéré quelques données du SDP que j'avais oublié (profile-level-id et sprop-parameter-set) afin d'alimenter les champs profile_idc, level_idc, extradata et extradata_size de ma structure AvCodecContext.
Ensuite j'ai séparé le décodage des paquets dits Coded Slice, SPS, PPS et NAL_IDR_SLICE.
Pour faire simple, les paquets Coded Slice allégés du header RTP sont directement passés au décodeur (avcodec_decode_video) avec le préfixe 0x000001. La fonction me renvoie bien la taille du paquet ConsumedBytes (indique que tous les bytes ont été utilisés pour le décodage) et le paramètre GotPicture indiquant que la frame est bien décodée devient supérieur à zéro à la suite du décodage.
Code:
1 2 3 4 5 6 7 8 9 10
|
uint8_t start_sequence[]= {0, 0, 1};
int size= recv(id_de_la_socket,(char*) rtpReceive,65535,0);
char *z = new char[size-16+sizeof(start_sequence)];
memcpy(z,&start_sequence,sizeof(start_sequence));
memcpy(z+sizeof(start_sequence),rtpReceive+16,size-16);
ConsumedBytes = avcodec_decode_video(codecContext,pFrame,&GotPicture,(uint8_t*)z,size-16+sizeof(start_sequence));
delete z; |
Les paquets SPS et PPS subissent les mêmes instructions. Cependant, le &GotPicture reste à zéro ce qui est normal.
A chaque fois qu'un nouveau couple SPS/PPS est trouvé, j'actualise les champs extradata et extradata_size de mon AvCodecContext. Cela devrait normalement me permettre de décoder ma prochaine Idr frame ...
Mes iDR Frame sont fragmentés selon le type FU-A. J'ai donc tenté deux méthodes pour les décoder :
1) à chaque fragment ayant le start_bit à 1, je lui préfixe la séquence 0x000001 et l'envoie à avcodec_decode_video. J'envoie le reste des fragments FU-A jusqu'au paquet ayant le end_bit =1.
2) je préfixe la séquence 0x000001 au premier paquet FU-A et lui concatène ensuite tous les autres fragments arrivant. Une fois de dernier fragment arrivé, j'envoie cette chaîne au décodeur.
Dans les deux cas la fonction ne me renvoie pas d'erreurs (ConsumedBytes >0) cependant elle ne détecte aucune frame (GotPicture reste à zéro).
Avez-vous des idées ? Qu'est-ce que je règle mal ? Quelle autre méthode puis-je employer ?
Merci d'avance