Problème de Décoder de la vidéo H264 sur RTP avec ffmpeg (libavcodec)
J'ai mis profile_idc, level_idc, extradata et extradata_size de AvCodecContext avec le profil de-niveau-id et sprop-paramètre de la SDP.
J'ai séparé le décodage de Codé Tranche, SPS, PPS et NAL_IDR_SLICE paquet :
Init:
u_int8_t start_sequence[]= {0, 0, 1};
int taille= recv(id_de_la_socket,(char*) rtpReceive,65535,0);
Codé Tranche :
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;
Résultat: ConsumedBytes >0 et GotPicture >0 (souvent)
SPS et PPS :
un code identique.
Résultat: ConsumedBytes >0 et GotPicture =0
C'est normal je pense
Quand je trouve un nouveau couple SPS/PPS, je l'ai mise à jour extradata et extrada_size avec les charges de ce paquet et leur taille.
NAL_IDR_SLICE :
Le dernier type d'unité est 28 =>idr Cadre sont fragmentés à cet effet que j'ai essayé deux méthode pour décoder
1) je préfixe le premier fragment (sans en-tête RTP) avec la séquence 0x000001 et de l'envoyer à avcodec_decode_video. Puis-je envoyer le reste des fragments de cette fonction.
2) j'ai préfixe le premier fragment (sans en-tête RTP) avec la séquence 0x000001 et concaténer le reste de fragments. J'envoie ce mémoire tampon de décodeur.
Dans les deux cas, je n'ai pas d'erreur (ConsumedBytes >0) mais je n'ai décelé aucun cadre (GotPicture = 0) ...
Quel est le problème ?
Pourquoi 0x000001? C'est h264 pas MPEG4.
Lire ma réponse encore une fois, je lui ai expliqué certaines choses qui pourraient vous concerner.
OriginalL'auteur bben | 2010-08-16
Vous devez vous connecter pour publier un commentaire.
Dans RTP tous H264 I-Frames (Idr) sont généralement fragmentés. Lorsque vous recevez RTP, vous devez d'abord ignorer l'en-tête (généralement 12 premiers octets) et puis se rendre à la dernière unité (premier octet de la charge utile). Si la NALE est de 28 (1C), alors cela signifie que, à la suite de la charge utile représente un H264 IDR (I-Frame) fragment et que vous avez besoin de collecter tous d'entre eux pour reconstruire H264 IDR (I-Frame).
La Fragmentation se produit parce que le MTU, et beaucoup plus IDR. Un fragment peut ressembler à ceci:
Fragment qui a un DÉBUT BIT = 1:
D'autres fragments:
De reconstruire IDR vous devez collecter cette info:
Si
fragment_type == 28
puis charge la suite c'est un fragment de l'IDR. Prochain contrôle eststart_bit
ensemble, si elle l'est, alors que le fragment est le premier d'une séquence. Vous pouvez l'utiliser pour reconstruire IDR dernier octet en prenant les 3 premiers bits du premier octet de la charge utile(3 NAL UNIT BITS)
et les combiner avec les 5 derniers bits du deuxième octet de la charge utile(5 NAL UNIT BITS)
donc, vous obtiendrez un octet comme ce[3 NAL UNIT BITS | 5 NAL UNIT BITS]
. Puis écrire que NAL octet d'abord dans un effacer la mémoire avec tous les autres suite d'octets à partir de ce fragment. N'oubliez pas de sauter le premier octet d'une séquence puisqu'il n'est pas une partie de l'IDR, mais identifie uniquement le fragment.Si
start_bit
etend_bit
sont 0, alors il suffit d'écrire la charge utile (en ignorant premier octet de la charge utile qui identifie le fragment) de la mémoire tampon.Si start_bit est 0 et end_bit est de 1, ce qui signifie qu'il est le dernier fragment, et vous venez d'écrire, sa charge utile (en ignorant le premier octet qui identifie le fragment) de la mémoire tampon, et maintenant vous avez votre IDR reconstruit.
Si vous avez besoin d'un code, il suffit de demander dans un commentaire, je vais poster ça, mais je pense que c'est assez clair comment faire... =)
CONCERNANT LE DÉCODAGE
Il a traversé mon esprit aujourd'hui pourquoi vous obtenez une erreur sur le décodage de l'IDR (je présume que vous avez reconstruit bon). Comment construisez-vous votre AVC Decoder Enregistrement de la Configuration? La lib que vous utilisez sont automatiques? Sinon et si vous havent entendu parler de cela, continuer la lecture...
AVCDCR est spécifié pour permettre décodeurs pour analyser rapidement toutes les données dont ils ont besoin pour décoder le H264 (AVC) flux vidéo. Et les données est la suivante:
Toutes ces données sont envoyées dans RTSP session SDP sous le champs:
profile-level-id
etsprop-parameter-sets
.DÉCODAGE PROFIL-NIVEAU-ID
Prifile niveau de l'ID de chaîne est divisée en 3 sous-chaînes, chacune de 2 caractères:
[PROFILE IDC][PROFILE IOP][LEVEL IDC]
Chaque sous-chaîne représente un octet dans base16! Donc, si le Profil de l'IDC est de 28, ce qui signifie qu'il est actuellement de 40 en base10. Plus tard, vous allez utiliser base10 valeurs pour construire AVC Decoder Enregistrement de la Configuration.
DÉCODAGE SPROP-PARAMÈTRE-ENSEMBLES
Sprops sont généralement 2 cordes (peut être plus) qui sont séparées par des virgules, et encodées en base64! Vous pouvez décoder les deux d'entre eux, mais il n'est pas nécessaire. Votre travail ici est juste de les convertir en base64 une chaîne en un tableau d'octets pour une utilisation ultérieure. Maintenant, vous avez 2 tableaux d'octets, le premier tableau nous SPS, le second, est PPS.
LA CONSTRUCTION DE LA AVCDCR
Maintenant, vous avez tout ce que vous devez construire AVCDCR, vous commencez par faire un nouveau propre tampon, maintenant, écris ces choses dans l'ordre expliqué ici:
1 Octet qui a de la valeur 1 et représente la version
2 - Profil de l'IDC octet
3 - Prifile IOP octet
4 - Niveau IDC octet
5 Octets dont la valeur 0xFF (google AVC Decoder Configuration de l'Enregistrement pour voir ce que c'est)
6 Octets dont la valeur 0xE1
7 - Court avec la valeur de la SPS longueur du tableau
8 - SPS tableau d'octets
9 - Octet avec le nombre de PPS tableaux (vous pourriez avoir de plus en plus dans sprop-paramètre)
10 - Court avec la longueur de la suite PPS tableau
11 - PPS tableau
DÉCODAGE DE FLUX VIDÉO
Maintenant, vous avez le tableau d'octets qui indique au décodeur comment décoder les flux vidéo H264. Je crois que vous avez besoin de cette si votre lib n'est pas le construire lui-même à partir de SDP...
Ok, alors vous n'êtes pas la reconstruction de IDR, comme vous devriez... à vérifier une fois de plus le processus. Espère que j'ai aidé... =)
C'est bon: ACDR est reconnu par le décodeur et les paramètres sont définis. Décodeur ne décode pas le reste, mais elle est due à un autre paramètres de ffmpeg, je pense. Je vous remercie pour votre aide : j'ai déjà fait d'importants progrès.
C'est vraiment une bonne réponse, malheureusement, vous avez écrit le deuxième octet de la FU-UN incorrect. Il devrait être [ START | END | RÉSERVÉ | TYPE ] c'est la FIN et RÉSERVÉE doit changer de place. Voir RFC3984 (ietf.org/rfc/rfc3984.txt).
Oui je vois, merci pour le commentaire! J'ai fait la
start_bit
et laend_bit
bits de masquage de la bonne pensée... 😛OriginalL'auteur Cipi
Je ne sais pas pour le reste de votre mise en œuvre, mais il semble probable que les "fragments", vous recevez sont des unités NAL. Par conséquent, chaque, chacun peut avoir besoin le NALU start-code (
00 00 01
ou00 00 00 01
) ajouté lorsque vous reconstruire le bitstream avant de l'envoyer à ffmpeg.En tout cas, vous trouverez peut-être les RFC pour H264 RTP packetization utile:
http://www.rfc-editor.org/rfc/rfc3984.txt
Espérons que cette aide!
Vous n'avez pas besoin de le faire... les Fragments sont des parties d'une IDR. NALU n'est transmise que dans le premier fragment, pas chacun. Pour le décoder, vous n'avez pas besoin d'ajouter le code de départ, car NALE de l'unité définit le H264 charge utile qui la suit (inférieur à 5 bits).
OriginalL'auteur Scott
J'ai une mise en œuvre de cette @ https://net7mma.codeplex.com/ pour c#, mais le processus est le même partout.
Voici le code
Il y a aussi des implémentations pour diverses autres RFC), qui aident à mettre les médias à jouer dans un MediaElement ou dans d'autres logiciels ou tout simplement l'enregistrer sur le disque.
Écrit à un format de conteneur est en cours.
OriginalL'auteur Jay