2016-07-07 2 views
2

Insights pour encoder/décodage vidéo avec h264 ffmpeg (sans perte)C++ h264 ffmpeg/libav encode/decode (sans perte) émet

Je suis quelque chose de travail de la part de l'encodage, encodez un fichier AVI en 264 mais VLC jouer wont il, cependant Totem sera. Décoder le même fichier s'avère gênant. (Je veux exactement les mêmes données/cadre que de sortir), je les reçois;

saving frame 5 
Video decoding 
[h264 @ 0x1d19880] decode_slice_header error 
frame :6 
saving frame 6 
Video decoding 
[h264 @ 0x1d19880] error while decoding MB 15 7, bytestream -27 
[h264 @ 0x1d19880] concealing 194 DC, 194 AC, 194 MV errors in I frame 
frame :7 
saving frame 7 
Video decoding 
[h264 @ 0x1d19880] decode_slice_header error 

et ultimatly ce

[H264 Decoder @ 0x7f1320766040] frame :11 
Broken frame packetizing 
[h264 @ 0x1d19880] SPS changed in the middle of the frame 
[h264 @ 0x1d19880] decode_slice_header error 
[h264 @ 0x1d19880] no frame! 
Error while decoding frame 11 

GAME OVER. Maintenant, je soupçonne que je dois revenir à 1. la partie encodage, il y a une bonne raison pour laquelle VLC ne la jouera pas!

Je code comme ça.

void encode(char *Y,char *U,char *V){ 
av_init_packet(&pkt); 
pkt.data = NULL; // packet data will be allocated by the encoder 
pkt.size = 0; 
fflush(stdout); 

frame->data[0] = (uint8_t*)Y; 
frame->data[1] = (uint8_t*)U; 
frame->data[2] = (uint8_t*)V; 
frame->pts = ++i; 

ret = avcodec_encode_video2(c, &pkt, frame, &got_output); 
if (ret < 0) { 
    fprintf(stderr, "Error encoding frame\n"); 
    exit (EXIT_FAILURE); 
} 
if (got_output) { 
    printf("Write frame %3d (size=%5d)\n", i, pkt.size); 
    fwrite(pkt.data, 1, pkt.size, f); 
    av_free_packet(&pkt); 
} 
} 

Et le codec est configuré comme ceci:

AVCodecID dasd = AV_CODEC_ID_H264; 
codec = avcodec_find_encoder(dasd); 
c = avcodec_alloc_context3(codec); 
c->bit_rate = 400000; 
c->width = 320; 
c->height = 240; 
c->time_base= (AVRational){1,25}; 
c->gop_size = 10; 
c->max_b_frames=1; 
c->pix_fmt = AV_PIX_FMT_YUV420P; 
av_opt_set(c->priv_data, "preset", "slow", 0); 
avcodec_open2(c, codec, NULL); 

Depuis que je vais faire sans perte je ne traite pas avec des cadres retardés (? Est-ce une hypothèse correcte) Je ne peux pas réellement encoderez sans perte, il semble que je dois aller avec quelque chose comme

AVDictionary *param; 
av_dict_set(&param, "qp", "0", 0); 

Et puis ouvrez ...

Je suppose que des questions me sont ces:

  • Quels sont les codec params pour l'encodage sans perte (et des conseils si H264 est une très mauvaise idée à cet égard).
  • Ai-je besoin de gérer des trames retardées lorsque je fais un test sans perte?
  • Pourquoi VLC est-il en colère contre moi?

Merci.

Répondre

1
  1. Pour obtenir sans perte: av_dict_set (& param, "crf", "0", 0);
  2. Les images retardées (images B) n'ont rien à voir avec la technologie sans perte. Si vous avez besoin d'un faible délai, n'utilisez pas de B-frames.

Quelque chose ne va vraiment pas dans votre encodage. L'erreur "MV errors in I frame" est bizarre ici, il ne devrait pas y avoir de MV dans I-frame. Il semble que l'en-tête l'analyse elle-même. S'il vous plaît partager le flux de bits & plus de détails pour l'échec de VLC

+0

Merci, je le ferai. Quand je rentre à la maison, je travaille sur un ordinateur portable que je viens de supposer est né avec une webcam intégrée .. j'avais tort. – MrSmith

1

Vous écrivez les cadres d'annexb bruts dans un fichier sans emballage de récipient. Utilisez un conteneur comme mp4 ou matroska et VLC devrait être heureux.

+0

Je vais regarder comment cela se fait, merci – MrSmith

-1

Alors, j'ai emballé celui-ci. Figured Id poster mes conclusions ici car il y a beaucoup d'informations semi-valides de travail outthere .. Ou peut-être juste de travailler dans des circonstances différentes de la mienne, c'est mon code:

init code. - La première chose à noter ici est av_guess_format "avi" pas "mp4" ou quoi que ce soit d'autre exotique pour h264 - La deuxième chose est, ne pas gâcher avec bitrate !! Cela me rendait fou car tous les échantillons que j'ai trouvés en ligne l'avaient mis en place. Laissez-le tranquille et contrôlez la qualité via "av_opt_set (ctx-> priv_data," crf "," 0 ", 0);". Lorsque j'avais un débit réglé, la qualité de l'encodage qui en résulte se détériorait au fil du temps jusqu'à ce que les images ne soient plus qu'un flou. - Troisièmement, utilisez avio_open et avformat_write_header au lieu de jongler avec votre propre gestion de fichiers.

// av_log_set_level(AV_LOG_DEBUG); 
av_register_all(); 
avcodec_register_all(); 
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); // 
AVOutputFormat * outputFormat = av_guess_format("avi", NULL, NULL); 
outFmtCtx = NULL; 
int test = avformat_alloc_output_context2(&outFmtCtx, outputFormat, NULL, NULL); 
if(test<0) exit(-1); 
avstream = avformat_new_stream(outFmtCtx, codec); 
avstream->time_base= (AVRational){1,25};; 


avcodec_get_context_defaults3(avstream->codec, codec); 
AVCodecContext *ctx = avstream->codec; 

// ctx->bit_rate = 1000000; // messing with this POS is just gonna get you brainpain .. dont do it man.. 
ctx->width = 320; 
ctx->height = 240; 
//ctx->time_base= (AVRational){1,25}; 
ctx->gop_size = 10; /* emit one intra frame every ten frames */ 
ctx->max_b_frames=10; 
ctx->pix_fmt = AV_PIX_FMT_YUV420P; 

// FOR H264 ONLY 
av_opt_set(ctx->priv_data, "preset", "slow", 0); 
// av_opt_set(ctx->priv_data, "crf", "0", 0); // 17 megs for 35 secs ... without : 900k 

// FOR H264 ONLY 

test = av_opt_set(avstream->codec->priv_data, "preset", "slow", 0); 
if(test<0) exit(-2); 
test = avcodec_open2(avstream->codec, codec, NULL); 
if(test<0) exit(-3); 
test = avio_open2(&outFmtCtx->pb, filenamhen, AVIO_FLAG_WRITE, NULL, NULL); 
if(test<0) exit(-4); 

test = avformat_write_header(outFmtCtx, NULL); 
if(test<0) exit(-5); 
frame = avcodec_alloc_frame(); 
if (!frame) exit(-6); 

frame->format = avstream->codec->pix_fmt; 
frame->width = avstream->codec->width; 
frame->height = avstream->codec->height; 

ret = av_image_alloc(frame->data, frame->linesize, frame->width, frame->height, avstream->codec->pix_fmt, 32); 
if (ret < 0) exit(-7); 

Codage de l'alimentation en direct. J'ai laissé du code ici non commenté pour revoir le plaisir. Selon les docs, cela devrait être légal, rattraper les délais et continuer. Ce ne est pas, donc ne :), nous le ferons dans le dernier bit quand nous fermons boutique et écrire la bande-annonce

pkt.data = NULL; 
pkt.size = 0; 
av_init_packet(&pkt); 

frame->data[0] = (uint8_t*)Y; 
frame->data[1] = (uint8_t*)U; 
frame->data[2] = (uint8_t*)V; 
frame->pts = i; 

ret = avcodec_encode_video2(avstream->codec, &pkt, frame, &got_output); 
if (ret < 0) { 
    fprintf(stderr, "Error encoding frame\n"); 
    exit (EXIT_FAILURE); 
} 
if (got_output) { 
    printf("Write frame %3d (size=%5d)\n", i, pkt.size); 
    //fwrite(pkt.data, 1, pkt.size, file_encoded_video); 
    // av_write_frame(outFmtCtx, &pkt); 
    av_interleaved_write_frame(outFmtCtx, &pkt); 
    av_free_packet(&pkt); 
} 
/* 
for (got_output = 1; got_output; i++) { 
    fflush(stdout); 
    ret = avcodec_encode_video2(avstream->codec, &pkt, NULL, &got_output); 
    if (ret < 0) { 
     fprintf(stderr, "Error encoding frame\n"); 
     exit(1); 
    } 

    if (got_output) { 
     printf("Write dealyed frame %3d (size=%5d)\n", i, pkt.size); 
     // av_write_frame(outFmtCtx, &pkt); 
     av_interleaved_write_frame(outFmtCtx, &pkt); 
     av_free_packet(&pkt); 
    } 
} 
*/ 

}

et une boutique de clôture. - Rédiger les images retardées - Ecrire remorque - ruisseau, à proximité:

pkt.data = NULL; 
pkt.size = 0; 
av_init_packet(&pkt); 
for (got_output = 1; got_output; i++) { 
     fflush(stdout); 
     ret = avcodec_encode_video2(avstream->codec, &pkt, NULL, &got_output); 
     if (ret < 0) { 
      fprintf(stderr, "Error encoding frame\n"); 
      exit(1); 
     } 

     if (got_output) { 
      printf("Write dealyed frame %3d (size=%5d)\n", i, pkt.size); 
      // av_write_frame(outFmtCtx, &pkt); 
      av_interleaved_write_frame(outFmtCtx, &pkt); 
      av_free_packet(&pkt); 
     } 
    } 
av_write_trailer(outFmtCtx); 
avio_close(outFmtCtx->pb); 

Hope this helps quelqu'un d'autre kung-fu-googler outthere :).