2010-05-28 3 views
0

J'ai une classe Objective-C (bien que je ne pense pas que ce soit quelque chose d'Obj-C) que j'utilise pour écrire une vidéo sur disque à partir d'une série d'images CG. (Le code que j'utilise en haut pour obtenir les données de pixels vient directement d'Apple: http://developer.apple.com/mac/library/qa/qa2007/qa1509.html). J'ai réussi à créer le codec et le contexte - tout va bien jusqu'à ce qu'il arrive à avcodec_encode_video, quand j'obtiens EXC_BAD_ACCESS. Je pense que cela devrait être une solution simple, mais je ne peux pas comprendre où je vais mal.EXC_BAD_ACCESS lors de l'appel de avcodec_encode_video

J'ai supprimé une vérification d'erreur pour la concision. 'c' est un AVCodecContext * qui a été créé avec succès.

-(void)addFrame:(CGImageRef)img 
{ 
    CFDataRef bitmapData = CGDataProviderCopyData(CGImageGetDataProvider(img)); 
    long dataLength = CFDataGetLength(bitmapData); 
    uint8_t* picture_buff = (uint8_t*)malloc(dataLength); 
    CFDataGetBytes(bitmapData, CFRangeMake(0, dataLength), picture_buff); 

    AVFrame *picture = avcodec_alloc_frame(); 
    avpicture_fill((AVPicture*)picture, picture_buff, c->pix_fmt, c->width, c->height); 

    int outbuf_size = avpicture_get_size(c->pix_fmt, c->width, c->height); 
    uint8_t *outbuf = (uint8_t*)av_malloc(outbuf_size); 

    out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture); // ERROR occurs here 
    printf("encoding frame %3d (size=%5d)\n", i, out_size); 
    fwrite(outbuf, 1, out_size, f); 

    CFRelease(bitmapData); 
    free(picture_buff); 
    free(outbuf); 
    av_free(picture); 
    i++; 
} 

Je l'ai traversé des douzaines de fois. Voici quelques chiffres ...

  1. dataLength = 408960
  2. picture_buff = 0x5c85000
  3. peinture-> données [0] = 0x5c85000 - que je considère dire que avpicture_fill a travaillé ...
  4. outbuf_size = 408960

puis j'obtiens EXC_BAD_ACCESS à avcodec_encode_video. Je ne sais pas si c'est pertinent, mais la plupart de ce code provient d'api-example.c. J'utilise XCode, compilant pour armv6/armv7 sur Snow Leopard.

Merci d'avance pour votre aide!

+0

Avez-vous déjà trouvé la solution? – skorulis

Répondre

0

J'ai pas assez d'informations ici pour indiquer l'erreur exacte, mais je pense que le problème est que l'image d'entrée contient moins de données que avcodec_encode_video() prévoit:

avpicture_fill() définit seulement quelques pointeurs et numérique valeurs dans la structure AVFrame. Il ne copie rien, et ne vérifie pas si le tampon est assez grand (et il ne peut pas, puisque la taille de la mémoire tampon ne lui est pas transmise). Il fait quelque chose comme ça (copié à partir des sources de ffmpeg):

size = picture->linesize[0] * height; 
    picture->data[0] = ptr; 
    picture->data[1] = picture->data[0] + size; 
    picture->data[2] = picture->data[1] + size2; 
    picture->data[3] = picture->data[1] + size2 + size2; 

Notez que la largeur et la hauteur est passé de la variable « c » (le AVCodecContext, je suppose), il peut être plus grande que la taille réelle du cadre d'entrée.

Il est également possible que la largeur/hauteur soit bonne, mais le format de pixel du cadre d'entrée est différent de ce qui est passé à avpicture_fill(). (Notez que le format de pixel provient également de AVCodecContext, qui peut différer de l'entrée). Par exemple, si c-> pix_fmt est RGBA et que le tampon d'entrée est au format YUV420 (ou, plus probablement pour l'iPhone, un biplanar YCbCr), alors la taille du tampon d'entrée est width * height * 1.5, mais avpicture_fill() attend la taille de la largeur * hauteur * 4. Par conséquent, la vérification de la géométrie d'entrée/de sortie et des formats de pixels devrait vous indiquer la cause de l'erreur. Si cela ne vous aide pas, je suggère que vous devriez d'abord essayer de compiler pour i386. Il est difficile de compiler correctement FFMPEG pour l'iPhone. Le codec que vous codez prend-il en charge l'espace colorimétrique RVB?

+0

Merci beaucoup pour votre réponse! Juste comme un test, j'ai fait agrandir le fichier picture_buff 10x, et j'ai la même erreur. La source que vous avez copiée attend une image (planaire) PIX_FMT_YUV420P, ce qui est, je suppose, la raison pour laquelle elle définit les 4 pointeurs différents - elle pointe vers le début de chaque canal. Je suppose que je aurais dû mentionner que, dans mon cas, c-> pix_fmt = PIX_FMT_RGB24 Je fais aussi un chèque:! if (CGImageGetWidth (img) = c-> || largeur CGImageGetHeight (img de) = c- > height) { NSLog (@ "Le cadre ne correspond pas à la taille du film. retour; } Quelles autres informations puis-je vous fournir? –

+0

Ou - pour m'aider, je devrais dire :) –

+0

Eh bien, alors je pense que le bug n'est pas ici, mais dans le code d'initialisation du codec - ce qui est beaucoup plus difficile à déboguer :(Ce qui est le plus probable est que vous n'avez pas mis Certains paramètres dans AVCodecContext Vous devriez vérifier les commentaires dans avcodec.h pour voir ce qui manque.Si cela ne vous aide pas, il ne reste plus qu'à déboguer le code ffmpeg ... (cela aide en fait si vous avez fait une erreur triviale!) Est-ce qu'il plante juste dans avcodec_encode_video()? Parce que dans cette fonction je ne vois qu'une chose à planter: si codecContext-> codec est NULL (avez-vous appelé av_register_all()?) – gyim

0

Vous devrez peut-être utiliser libswscale pour convertir en I420 avant l'encodage. Quel codec utilisez-vous? Pouvez-vous poster le code où vous initialisez votre contexte de codec?

+0

H.264 prend en charge RVB. Mpeg4 n'a pas. J'ai essayé les deux. En ce moment, je prends le contexte et le codec directement à partir du code qui ouvre la vidéo. Y at-il une raison pour que cela ne fonctionne pas? Auteur: http://github.com/jefftimesten/Unlogo/blob/master/Classes/VideoMaker.m –

Questions connexes